Angular4 PrimeNG DataTable不更新,尽管模型发生了变化。

时间:2023-01-20 20:34:36

I get an observable back from a data service to web api that returns an array and populates a data table in a parent component correctly. I pass the array used to populate the datatable to a child component via @Input. When a row on the parent component is clicked, I show a modal for editing a single row using a Form. When the save button is clicked on the modal, the row information is sent to the child component which calls to the server and updates the information correctly. The server returns the updated object which is then spliced into the @Input array. The datatable never updates although I can see that the changes to the model array do occur and are detected by Angular by using Augury. I've tried using NgZone, NgOnChanges and setters/getters to have the array forced to update, to no avail. I have this exact same code in another project, and it works as expected. I'm not sure what I'm missing here.

我从数据服务获得了一个可观察到的从返回一个数组并正确填充父组件中的数据表的web api。通过@Input将用于填充数据表的数组传递给子组件。当单击父组件上的一行时,我将显示使用窗体编辑单个行的模式。当在模式上单击save按钮时,行信息被发送到调用服务器并正确更新信息的子组件。服务器返回已更新的对象,然后将其拼接到@Input数组中。虽然我可以看到模型阵列的变化确实发生了,并且通过使用Augury来检测到,但是datatable从不更新。我尝试过使用NgZone、NgOnChanges和setter /getter来让数组被强制更新,但是没有效果。在另一个项目中,我有完全相同的代码,它按预期工作。我不知道我在这里错过了什么。

Parent Template

父模板

<h2>Website Aliases</h2>

<p-dataTable #dt [value]="websiteAliases" selectionMode="single" [(selection)]="selectedWebsiteAlias"
             (onRowSelect)="onRowSelect($event);wad.setEditValue(selectedWebsiteAlias)"
             [paginator]="true" [rows]="100"
             [sortMode]="multiple">
    <p-header>
        Website Aliases
        <div style="float:right;">
            <button pButton type="button" (click)="wad.setCreateValue();" icon="fa-plus"></button>
            <button pButton type="button" (click)="reloadDataTable();" icon="fa-refresh"></button>
        </div>
    </p-header>
    <p-column field="aliasID" header="Alias ID" sortable="true"></p-column>
    <p-column field="webID" header="Web ID" [filter]="true" filterMatchMode="contains"></p-column>
    <p-column field="csHost" header="CsHost" [filter]="true" filterMatchMode="contains"></p-column>
</p-dataTable>

    <website-alias-detail #wad [websiteAlias]="selectedWebsiteAlias" [websiteAliases]="websiteAliases"></website-alias-detail>

Parent Component

父组件

import { Observable } from 'rxjs/Rx';
import { DataTableModule, DialogModule } from 'primeng/primeng';
import { WebsiteAliasDetailComponent } from './websitealiasdetails.component';

@Component({
    selector: 'website-alias',
    templateUrl: 'websitealias.component.html'
})

export class WebsiteAliasComponent {
    constructor(private dataService: DataService) { }
    private websiteAliases: WebsiteAlias[];
    private selectedWebsiteAlias: WebsiteAlias;


    ngOnInit(): void {
        this.dataService.get('websitealias').subscribe(apiObjects => this.websiteAliases = apiObjects);
    }

    onRowSelect(row): void {
        this.selectedWebsiteAlias = this.websiteAliases.find(websiteAlias => websiteAlias.aliasID === row.data.aliasID);
    }

    createWebsiteAlias(): void {
        this.selectedWebsiteAlias = null;
    }

    reloadDataTable(): void {
        this.dataService.get('websitealias').subscribe(apiObjects => this.websiteAliases = apiObjects);
    }
}

Child Template

子模板

<p-dialog #dialog modal="true" header="Website Alias Details" [(visible)]="display">
    <form #form [formGroup]="alias">
        <div class="alert alert-danger" [hidden]="alias.controls.webID.valid || (alias.controls.webID.pristine && !submitted)">
            Web ID is required and only accepts numbers
        </div>
        <div class="alert alert-danger" [hidden]="alias.controls.csHost.valid || (alias.controls.csHost.pristine && !submitted)">
            CS Host is required
        </div>
        <div class="divTable">
            <div class="divTableBody">
                <div class="divTableRow" *ngIf="alias">
                    <div class="divTableCell"><label>Alias ID:  </label></div>
                    <div class="divTableCell"><label><input placeholder="Alias ID" formControlName="aliasID" readonly="readonly" /></label></div>
                </div>
                <div class="divTableRow">
                    <div class="divTableCell"><label>Web ID:  </label></div>
                    <div class="divTableCell"><input placeholder="Web ID" formControlName="webID" /></div>
                </div>
                <div class="divTableRow">
                    <div class="divTableCell"><label>CS Host:   </label></div>
                    <div class="divTableCell"><input placeholder="CS Host" formControlName="csHost" /></div>
                </div>
                <div class="divTableRow">
                    <div class="divTableCell">
                        <button pButton type="submit" label="Save" (click)="saveWebsiteAlias(alias.value)" [disabled]="alias.invalid" class="ui-button ui-button-primary"></button>
                        <button pButton type="button" label="Close" (click)="hideDialog();" class="ui-button ui-button-secondary"></button>
                        <button *ngIf="websiteAlias" pButton type="submit" label="Delete" (click)="deleteWebsiteAlias(alias.value)" class="ui-button ui-button-danger"></button>
                    </div>
                </div>
            </div>
        </div>
    </form>
</p-dialog>

Child Component

子组件

import { Component, Input, Output, OnInit, ViewEncapsulation } from '@angular/core';
import { DataService } from '../../services/data.service';
import { WebsiteAlias } from './WebsiteAlias';
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';

@Component({
    selector: 'website-alias-detail',
    templateUrl: 'websitealiasdetails.component.html',
    encapsulation: ViewEncapsulation.None,

})

export class WebsiteAliasDetailComponent implements OnInit {
    @Input() websiteAliases: WebsiteAlias[];
    @Input() websiteAlias: WebsiteAlias;

    public alias: FormGroup;
    private api = 'websitealias';
    private display: boolean = false;
    private isEdited: boolean = false;

    constructor(private dataService: DataService, private formBuilder: FormBuilder) { }

    ngOnInit(): void {
        this.alias = this.formBuilder.group({
            aliasID: [''],
            webID: ['', [Validators.required, Validators.pattern('[0-9]*')]],
            csHost: ['',Validators.required]
        });

    }


    setEditValue(websiteAlias: WebsiteAlias)
    {
        this.alias.patchValue({ aliasID: websiteAlias.aliasID, webID: websiteAlias.webID, csHost: websiteAlias.csHost});
        this.isEdited = true;
        this.showDialog();
    }

    setCreateValue()
    {
        this.alias.patchValue({ aliasID: '', webID: '', csHost: '' });
        this.isEdited = false;
        this.websiteAlias = null;
        this.showDialog();
    }


    showDialog(): void {

        this.display = true;
    }

    hideDialog(): void {
        this.display = false;
    }

    saveWebsiteAlias(savedAlias: WebsiteAlias): void {

        if (!this.isEdited)
            this.createWebsiteAlias(savedAlias);            
        else {
            this.editWebsiteAlias(savedAlias);
        }

        this.hideDialog();
    }

    deleteWebsiteAlias(deletedAlias: WebsiteAlias): void {

        var idToDelete = 0;
        this.dataService.delete(this.api, deletedAlias.aliasID).subscribe(deletedId => idToDelete = deletedId);

        let websiteAliasToRemove = this.websiteAliases.find(web => web.aliasID === idToDelete);
        let index: number = this.websiteAliases.indexOf(websiteAliasToRemove);
        this.websiteAliases.splice(index, 1);

        this.hideDialog();

    }

    createWebsiteAlias(createdAlias: WebsiteAlias): void {

        var newAlias = new WebsiteAlias(0, createdAlias.webID, createdAlias.csHost);

        this.dataService.post(this.api, newAlias).subscribe(apiObject => newAlias.aliasID = apiObject.aliasID);

        this.websiteAliases.push(newAlias);
        this.websiteAlias = newAlias;

    }

    editWebsiteAlias(updatedAlias: WebsiteAlias): void {
        var idToUpdate = 0;
        var aliases = this.websiteAliases;
        this.dataService.put(this.api, updatedAlias).subscribe(apiObject => this.websiteAlias = apiObject);
        let websiteAliasToEdit = aliases.find(web => web.aliasID === updatedAlias.aliasID);
        let index: number = aliases.indexOf(websiteAliasToEdit);
        this.websiteAliases.splice(index, 1, updatedAlias);
    }

}

1 个解决方案

#1


2  

Look at the answer given in [How to programmaticaly trigger refresh primeNG datatable when a button is clicked question: 1

看看这个答案,当一个按钮被点击的时候,它会触发刷新primeNG datatable: 1。

I don't have enough rep to add this as a comment, but the answer involves creating a "visible" variable with *ngIf to trigger recreating the DOm.

我没有足够的代表来添加这个注释,但是答案是创建一个带有*ngIf的“可见”变量,以触发重新创建DOm。

#1


2  

Look at the answer given in [How to programmaticaly trigger refresh primeNG datatable when a button is clicked question: 1

看看这个答案,当一个按钮被点击的时候,它会触发刷新primeNG datatable: 1。

I don't have enough rep to add this as a comment, but the answer involves creating a "visible" variable with *ngIf to trigger recreating the DOm.

我没有足够的代表来添加这个注释,但是答案是创建一个带有*ngIf的“可见”变量,以触发重新创建DOm。