I get the observable back from the data service to the web api, which returns an array and correctly populates the data table in the parent component. I pass the array used to populate the datatable with the child component via @Input. When a line is clicked on the parent component, I will show a modal for editing one line using the form. When the save button is pressed on the modal, the line information is sent to the child component, which calls the server and correctly updates the information. The server returns an updated object, which is then merged into an @Input array. The data is never updated, although I see that changes in the model array occur and are detected using Angular using Augury. I tried using NgZone, NgOnChanges, and setters / getters to force the array to force update, but to no avail.I have this exact code in another project, and it works as expected. I'm not sure what I am missing here.
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);
}
}
Kids pattern
<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);
}
}