Closed muhammadarsal closed 7 years ago
Asynchronously fetched data shows up in the placeholder, but when I try to change it, I get an "ExpressionChangedAfterItHasBeenCheckedError"
ngOnInit(): void {
this.ajax = {
url: 'http://raspi/rest/api/users',
dataType: 'json',
delay: 250,
data: function (params) {
return {
q: params.term, // search term
page: params.page
};
},
cache: true
};
this.options = {
ajax: this.ajax,
multiple: true,
minimumInputLength: 1,
}
this.route.paramMap
.switchMap((params: ParamMap) =>
this.featureService.getFeature(params.get('program'), params.get('fid')))
.subscribe(feature => this.feature = feature);
}
template:
<div *ngFor="let u of feature.units">
<ng-select2 [(ngModel)]="u.owners" [data]="u.owners" [width]="300" [options]="options"></ng-select2>
</div>
Feature Object:
{
"_id":{"$oid":"59a79739696f825957622ef2"},
"program":"myProgram",
"units":[
{
"name":"bpic",
"description":"Branch Prediction & Instruction Cache",
"status":"Not Started",
"owners":["Batman","Superman"]
},
{
"name":"lsdc",
"description":"Load-Store and Data Cache",
"status":"Started",
"owners":["Aquaman"]
}
],
"fid":"BP03",
"name":"BP feature three"
}
If I try to add Aquaman to the bpic owners list:
ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'Batman,Superman,Aquaman'. Current value: 'Batman,Superman'
Its as if there's a conflict between the 2-way-data-binding, and the "[data]" binding; the [data] binding overwrites the changes of the [(ngModel)] causing the error?
Apologies if I'm doing this wrong, I'm new to Angular.
Edit: Looks like it might be related to this: https://stackoverflow.com/questions/30316586/select2-4-0-0-initial-value-with-ajax#30328989
Maybe I should remove the "[data]" binding and somehow trigger the ('change')?
2-way data-binding here is used to bind the selected value. The mistake you're making here is that you're trying to use it to bind the data. You don't need ngModel for updating the data.
Change [(ngModel)]="u.owners"
to [(ngModel)]="selectedValue"
and you're good to go.
Thank you for the reply, but I couldn't get this to fix my issue?
u.owners
are the selected values (multiple: true). The only way I can get u.owners
to update with changes to the selection is to use [(ngModel)]="u.owners"
. I think the [data]
bind is supposed to supply the selectable options? The selectable options are the entire list of employees in my company, which is why I'm using ajax to filter that list based on the search terms?
So the part I'm confused about, is what I'm supposed to put in the [data]
bind, since that list is coming from ajax? I can't find any examples
Can you please show the code where you're trying to change the selected options?
If I set [(ngModel)]="selectedValue"
, I see the changes I make reflected in the contents of selectedValue.
However I want the initial selected values to be u.owners
foreach u of feature.units
. How do I initialize the selected values to u.owners
?
Edit: updated to avoid the need of the FeatureService
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, ParamMap } from '@angular/router';
import { Location } from '@angular/common';
import 'rxjs/add/operator/switchMap';
// import { Feature } from '../feature';
// import { FeatureService } from '../feature.service';
import { Observable } from 'rxjs/Observable';
// import { Select2OptionData } from 'ng-select2/ng-select2.interface';
@Component({
selector: 'app-feature-form',
templateUrl: './feature-form.component.html',
styleUrls: ['./feature-form.component.css']
})
export class FeatureEditComponent implements OnInit {
// feature = new Feature();
feature: any;
submitted = false;
title = 'Edit Feature';
selectedValue: string[];
public options: Select2Options;
public ajax: Select2AjaxOptions;
constructor(
// private featureService: FeatureService,
private route: ActivatedRoute,
private location: Location
) { }
onSubmit() {
this.submitted = true;
// this.featureService.update(this.feature)
// .then(() => this.goBack());
}
ngOnInit(): void {
this.ajax = {
url: 'http://jsonplaceholder.typicode.com/users',
dataType: 'json',
delay: 250,
data: function (params) {
return {
q: params.term, // search term
page: params.page
};
},
processResults: function (data) {
let i;
const res = new Array();
for (i = 0; i < data.length; i++) {
res[i] = {id: data[i]['username'], text: data[i]['username']};
}
console.log(res);
return {
results: res,
pagination: {
more: false
}
}
;
},
cache: true
};
this.options = {
ajax: this.ajax,
multiple: true,
minimumInputLength: 1,
}
/*
this.route.paramMap
.switchMap((params: ParamMap) =>
this.featureService.getFeature(params.get('program'), params.get('fid')))
.subscribe(feature => this.feature = feature);
*/
this.feature = {
'_id': {'$oid': '59a79739696f825957622ef2'},
'program': 'myProgram',
'units': [
{
name: 'bpic',
description: 'Branch Prediction & Instruction Cache',
status: 'Not Started',
owners: ['Bret']
},
{
name: 'lsdc',
description: 'Load-Store and Data Cache',
status: 'Started',
owners: ['Antonette']
}
],
fid: 'BP03',
name: 'BP feature three',
owner: []
};
}
goBack(): void {
this.location.back();
}
get diagnostic() { return this.feature && JSON.stringify(this.feature); }
}
Since the problem isn't related to this thread, we should move to private conversation
If the data is fetched asynchronously and the value is set before the data arrives, the selected value is not shown in the placeholder.