【问题标题】:How to add data dynamically to mat-table dataSource?如何将数据动态添加到 mat-table 数据源?
【发布时间】:2020-06-02 14:09:11
【问题描述】:

我有来自后端的数据流,我看到它在控制台中打印,现在我正在尝试将事件推送到dataSource 它的抛出错误数据源未定义。有人可以帮助如何动态添加数据以实现表吗?

stream.component.html

<mat-table #table [dataSource]="dataSource"></mat-table>

stream.component.ts

import {
    Component,
    OnInit
} from '@angular/core';
import {
    StreamService
} from '../stream.service';
import {
    MatTableDataSource
} from '@angular/material';
import * as io from 'socket.io-client';

@Component({
    selector: 'app-stream',
    templateUrl: './stream.component.html',
    styleUrls: ['./stream.component.css']
})
export class StreamComponent implements OnInit {
    displayedColumns = ['ticketNum', "assetID", "severity", "riskIndex", "riskValue", "ticketOpened", "lastModifiedDate", "eventType"];
    dataSource: MatTableDataSource < Element[] > ;
    socket = io();

    constructor(private streamService: StreamService) {};

    ngOnInit() {
        this.streamService.getAllStream().subscribe(stream => {
            this.dataSource = new MatTableDataSource(stream);
        });
        this.socket.on('newMessage', function(event) {
            console.log('Datasource', event);
            this.dataSource.MatTableDataSource.filteredData.push(event);
        });
    }
}


export interface Element {
    ticketNum: number;
    ticketOpened: number;
    eventType: string;
    riskIndex: string;
    riskValue: number;
    severity: string;
    lastModifiedDate: number;
    assetID: string;
}

【问题讨论】:

    标签: javascript angular angular-material2 angular5


    【解决方案1】:

    我已经找到了解决这个问题的方法,基本上如果你这样做:

    this.dataSource.data.push(newElement); //Doesn't work

    但是,如果您替换完整的数组,则它可以正常工作。所以你的最终代码必须是:

    this.socket.on('newMessage', function(event) {
        const data = this.dataSource.data;
        data.push(event);
        this.dataSource.data = data;
    });
    

    您可以在此处查看问题 -> https://github.com/angular/material2/issues/8381

    【讨论】:

    • S/O 评论:请尝试为您的链接添加一些上下文。简单地发布链接不会为您的答案增加价值。尝试浏览问题并总结答案中的相关部分。始终尽量做到全面。如果您解释您的代码,它也可能使提问者受益。不幸的是,像这样的代码块会鼓励未来观众的复制/粘贴行为。我们希望 S/O 用户在这里获得知识;所以如果你有它,分享它!
    • 更简洁优雅的方式:this.dataSource.data = { ...this.dataSource.data, event }
    • 使用this.table.renderRows()
    • this.dataSource.data = [ ...this.dataSource.data, 事件]
    • 这不是错误,dataSource 必须被视为不可变的。
    【解决方案2】:

    这是一个非常简单易行的解决方案:

    displayedColumns = ['ticketNum', 'assetID', 'severity', 'riskIndex', 'riskValue', 'ticketOpened', 'lastModifiedDate', 'eventType'];
    dataSource: any[] = [];
    
    constructor() { 
    
    }
    
    ngOnInit() {
    
    }
    
    onAdd() {  //If you want to add a new row in the dataSource
       let model = { 'ticketNum': 1, 'assetID': 2, 'severity': 3, 'riskIndex': 4, 'riskValue': 5, 'ticketOpened': true, 'lastModifiedDate': "2018-12-10", 'eventType': 'Add' };  //get the model from the form
       this.dataSource.push(model);  //add the new model object to the dataSource
       this.dataSource = [...this.dataSource];  //refresh the dataSource
    }
    

    希望这会有所帮助:)

    【讨论】:

    • 尝试了几乎所有的解决方案,但这是所有其他解决方案......谢谢
    【解决方案3】:

    以下解决方案对我有用:

    this.socket.on('newMessage', function(event) {
        this.dataSource.data.push(event);
        this.dataSource.data = this.dataSource.data.slice();
    });
    

    另一种解决方案是为 MatTableDataSource 对象调用 _updateChangeSubscription() 方法:

    this.socket.on('newMessage', function(event) {
        this.dataSource.data.push(event);
        this.dataSource._updateChangeSubscription();
    });
    

    这个方法:

    /** 订阅应触发更新表的呈现行的更改。当发生更改时,处理过滤器、排序和分页的当前状态以及提供的基础数据,并将其发送到表进行渲染。 */

    【讨论】:

    • this.dataSource.data = this.dataSource.data.slice(); 是不必要的,实际上可能会破坏 dataSource 与底层的连接。您可以使用this.dataSource.data = this.dataSource.data; 触发它,它不必(也不应该)通过切片/即新数组。
    • this.dataSource._updateChangeSubscription() 为我工作
    【解决方案4】:

    来自docs

    由于该表针对性能进行了优化,它不会自动检查对数据数组的更改。相反,当在数据数组上添加、删除或移动对象时,您可以通过调用其 renderRows() 方法来触发对表的渲染行的更新。

    所以,你可以使用 ViewChild 和 refreshRow()

    @ViewChild('table', { static: true }) table;
      add() {
        this.dataSource.data.push(ELEMENT_DATA[this.index++]);
        this.table.renderRows();
      }
    

    我在stackblitz中整理了一个例子

    【讨论】:

      【解决方案5】:

      如果您不使用 ES6+,也可以使用 ES6 扩展运算符或 concatdataSource 数据分配给新数组。

      在 ES6+ 中

      this.socket.on('newMessage', function(event) {
          this.dataSource.data = [...this.dataSource.data, event];
      });
      

      ECMAscript 版本 3+

      this.socket.on('newMessage', function(event) {
          this.dataSource.data = this.dataSource.data.concat(event);
      });
      

      【讨论】:

        【解决方案6】:

        在创建选择行并对行数据应用一些操作时,我遇到了同样的问题。这个解决你的问题

        imports..................
        import { MatTableDataSource } from '@angular/material';
        @component({ ...
        
        export class StreamComponent implements OnInit {
        // Initialise MatTableDataSource as empty
        dataSource = new MatTableDataSource<Element[]>();
        
        constructor() {}
        ...
        // if you simply push data in dataSource then indexed 0 element remain undefined
        // better way to do this as follows
         this.dataSource.data = val as any;
        
          // for your problem
        
           ngOnInit() {
          // ** important note .... I am giving solution assuming the subscription data is array of objects. Like in your case stream and in second event(parameter as callback)
            this.streamService.getAllStream().subscribe(stream => {
               // do it this way
                this.dataSource.data = stream as any;
             // note if you simply put it as 'this.dataSource.data = stream' then TS show you error as '[ts] Type 'string' is not assignable to type '{}[]''
            });
            this.socket.on('newMessage', (event) => {
                console.log('Datasource', event);
                  // for this value
               // this.dataSource.MatTableDataSource.filteredData.push(event);   // I couldn't get what you are doing here 
             // SO try to explain what you are getting in this callback function val as event parameter ????????????????? 
             // but you can get it this ways
        
               this.dataSource.filteredData = event as any;
            });
          }
        

        希望这会对您有所帮助。如果您有任何问题,请联系我。

        【讨论】:

          【解决方案7】:

          对我来说,这些答案都没有奏效。 我订阅了一个 observable 以获取新数据。 唯一适合我的解决方案是:

           this.dataService.pointsNodesObservable.subscribe((data) => {
            this.dataSource = new InsertionTableDataSource(this.paginator, this.sort, this.dataService);
            this.dataSource.data = data;
          });
          

          像魅力一样渲染!

          【讨论】:

          • 这是一个不完整的答案,没有包含 dataService 组件,并且违反了 SO 标准。
          猜你喜欢
          • 1970-01-01
          • 2021-02-20
          • 2012-07-05
          • 2018-03-26
          • 2018-06-02
          • 2018-05-08
          • 2018-10-22
          • 1970-01-01
          • 2016-07-05
          相关资源
          最近更新 更多