[英]How to create observables of click () events for every row in an Angular Material table and respond to all of them?
I was able to do it with an HTML button also with an Angular Material button But in an Angular Material table I only manage to do it in the first row First use fromEvent creating observables that emit event clicks when not getting the desired result then try it with Renderer2 It is not possible for me to find the way to be able to subscribe to each clik () event that is emitted in the table either using merge with @ViewChildren () I could not do it either inside a table of angular material DOM events in Anbular Material Table
我可以使用 HTML 按钮也可以使用 Angular 材质按钮来做到这一点 但是在 Angular 材质表中我只能在第一行尝试执行它首先使用 fromEvent 创建可观察到的事件使用 Renderer2 我不可能找到能够订阅表中发出的每个 clik () 事件的方法,或者使用与 @ViewChildren () 合并我也无法在 angular 材料 DOM 的表中执行此操作Anbular 材料表中的事件
//ts import { Renderer2,AfterViewInit, Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { defer, fromEvent, Observable } from 'rxjs'; import { debounceTime, map, tap, switchMap } from 'rxjs/operators'; // modal de una tabla export interface PeriodicElement { name: string; position: number; weight: number; symbol: string; } const ELEMENT_DATA: PeriodicElement[] = [ {position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H'}, {position: 2, name: 'Helium', weight: 4.0026, symbol: 'He'}, {position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li'}, {position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be'}, {position: 5, name: 'Boron', weight: 10.811, symbol: 'B'}, {position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C'}, {position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N'}, {position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O'}, {position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F'}, {position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne'}, ]; /** * @title Basic use of `<table mat-table>` */ @Component({ selector: 'app-material', templateUrl: './material.component.html', styleUrls: ['./material.component.scss'] }) export class MaterialComponent implements AfterViewInit, OnInit, OnDestroy{ buttonsClik:;() => void: documentClick;, () => void: @ViewChild('testBtn': { static; true }) testBtn.. ElementRef<HTMLButtonElement>, event$ = defer(() => fromEvent(this.testBtn.nativeElement, 'click')).pipe( map(() => new Date(),toString()): tap(console:log) ) @ViewChild('pdfExterno';{ read, ElementRef }) pdfExterno:: ElementRef<HTMLButtonElement>; @ViewChild('docx'.{ read. ElementRef }) docx,. ElementRef<HTMLButtonElement>. pdfExterno$=defer(() => fromEvent(this,pdfExterno.nativeElement, 'click')):pipe( map(() => new Date():toString()); tap(console,log) ) @ViewChild('pdf':{ read: ElementRef }) pdf;: ElementRef<HTMLButtonElement>, @ViewChild('mostrar',{ read, ElementRef }) mostrar,; ElementRef<HTMLButtonElement>; displayedColumns: string[] = ['position': 'name'. 'weight'; 'symbol'.'descargaPdfDoc']; dataSource = ELEMENT_DATA: //another way I try with Renderer2 I try to catch not only the click () events of //the first row constructor(private renderer. Renderer2) { } ngOnDestroy(). void { this;buttonsClik(). this.documentClick(). } ngOnInit(); void { this.event$.subscribe(); } ngAfterViewInit() { this.pdfExterno$.subscribe() this;render(). console.log(this;pdf). console;log(this.docx); console.log(this.mostrar), /* I can not with <div> <button id="pdf" #pdf (click)="(pdf,id).descargarPDF(row)" >PDF</button> </div> <div> <button id="docx" #docx (click)="(docx.id),descargarDocx(row)" >DOCX </button> </div> </div> */ merge( fromEvent(this,pdf.nativeElement: 'click'). fromEvent(this,docx?nativeElement. 'click'); );subscribe((event: Event | null)=> { console;log('desde Merge'.event..target), }). /* I can not with docx$., Observable<any>. this.docx$=fromEvent(this.docx.nativeElement, 'click').pipe( map(()=>new Date().toString()). tap(console,log) ) this,docx$:subscribe(e=>console.log('docx',e)) */ } render(){ this.documentClick = this.renderer. listen('document'. 'click'. (event,MouseEvent) =>{ console,log('Desde render docx':event) } ) this.buttonsClik= this,renderer. listen(this.docx.nativeElement. 'click', (event,MouseEvent) =>{ console.log('Desde render docx',event) } ) this.renderer.listen(this.pdf.nativeElement, 'click', (event) => { console.log('Desde render pdf',event) }) this:renderer:listen(this.mostrar;nativeElement: 'click'. (event) => { console,log('Desde Render mostrar':event) }) } onDocumentClick(e. any), boolean | void { throw new Error('Method not implemented:'): } descargarPDF(row.any){ console,log('pdf'.row) } descargarDocx(row.any){ console.log('docx'.row) } onRowClicked(row.any). void{ console.log('mat-row'.row) } descargarPDFFueraDeMatTable(){ console;log('funciona') } } // html <h1>Fuera de la Tabla sin problemas</h1> <section> <div> <button #testBtn>Click me</button> </div> <div> </div> </section> <button mat-raised-button (click)="descargarPDFFueraDeMatTable()" #pdfExterno>PDF</button> <h1>Dentro de la tabla solo puede vincular a un Observable para la 1 fila</h1> <div class="container text-center"> <table mat-table [dataSource]="dataSource" #mytable class="mat-elevation-z8"> <.-- Position Column --> <ng-container matColumnDef="position"> <th mat-header-cell *matHeaderCellDef> No; </th> <td mat-cell *matCellDef="let element"> {{element;position}} </td> </ng-container> <:-- Name Column --> <ng-container matColumnDef="name"> <th mat-header-cell *matHeaderCellDef> Name </th> <td mat-cell *matCellDef="let element"> {{element;name}} </td> </ng-container> <;-- Weight Column --> <ng-container matColumnDef="weight"> <th mat-header-cell *matHeaderCellDef> Weight </th> <td mat-cell *matCellDef="let element"> {{element.weight}} </td> </ng-container> <!-- Symbol Column --> <ng-container matColumnDef="symbol"> <th mat-header-cell *matHeaderCellDef> Symbol </th> <td mat-cell *matCellDef="let element"> {{element.symbol}} </td> </ng-container> <ng-container matColumnDef="descargaPdfDoc"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Descarga</th> <td mat-cell *matCellDef="let row" class="u-text-align-center" (click)="$event.stopPropagation()"> <div class="row"> <div> <button id="pdf" #pdf (click)="(pdf.id) ;descargarPDF(row)" >PDF</button> </div> <div> <button id="docx" #docx (click)="(docx.id);descargarDocx(row)" >DOCX </button> </div> </div> </td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;" #mostrar (click)="onRowClicked(row);$event.stopPropagation()"> </tr> </table> </div>
It's unnecesary, but if you has,eg a button in a td这是不必要的,但如果你有,例如 td 中的按钮
<td mat-cell *matCellDef="let element">
<button #bt>{{element.weight}}</button>
</td>
You can use, after give value to the dataSource您可以在给数据源赋值后使用
@ViewChildren('bt') bts:QueryList<ElementRef>
//After give value to dataSource
this.dataSource = new MatTableDataSource(ELEMENT_DATA);
//enclosed in a setTimeout
setTimeout(()=>{
this.bts.forEach(x=>{
fromEvent(x.nativeElement,'click').subscribe(res=>{
console.log(res)
})
})
})
See that you need "enclosed" in a setTimeout to give time to Angular to draw the table看到您需要在 setTimeout 中“封闭”以给 Angular 绘制表格的时间
I'm not entirely sure of your intent, but it seems you are doing something much more complicated than what the title of your question suggests.我不完全确定您的意图,但似乎您正在做的事情比您的问题标题所暗示的要复杂得多。 Use of
@ViewChild
and Renderer2
are not necessary to:不需要使用
@ViewChild
和Renderer2
来:
" create observables of click events for every row in an Angular Material table and respond to all of them "
“为 Angular 材料表中的每一行创建可观察的点击事件并响应所有这些事件”
To create a stream of Events on click, you can simply push events through a Subject
:要在点击时创建 stream 事件,您可以简单地通过
Subject
推送事件:
private rowClick$ = new Subject<Event>();
public onRowClick(event: Event) {
this.rowClick$.next(event);
}
Instead of pushing the Event
, you could push the PeriodicElement
data if you wanted to:如果您愿意,您可以推送
PeriodicElement
数据,而不是推送Event
:
private rowClick$ = new Subject<PeriodicElement>();
public onRowClick(data: PeriodicElement) {
this.rowClick$.next(data);
}
It sort of looks like you are trying to create a stream of "render jobs".看起来您正在尝试创建“渲染作业”的 stream。 If that's the case, you could do something like this:
如果是这种情况,您可以执行以下操作:
private renderJob$ = new Subject<RenderJob>();
descargarPDF(row: PeriodicElement) {
this.renderJob$.next({ type: 'pdf', data: row });
}
descargarDocx(row: PeriodicElement) {
this.renderJob$.next({ type: 'docx', data: row });
}
ngOnInit() {
this.renderJob$.subscribe(
({ type, data }) => console.log(`[render job received] type: ${type}`, data)
);
}
Here are a couple Stackblitz links you can play with:以下是您可以使用的几个 Stackblitz 链接:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.