muhammadarsal / ng-select2

Angular 4 wrapper for jQuery select2
7 stars 39 forks source link

when using dynamic data, selected value doesn't show in the placeholder #2

Closed muhammadarsal closed 7 years ago

muhammadarsal commented 7 years ago

If the data is fetched asynchronously and the value is set before the data arrives, the selected value is not shown in the placeholder.

ctung commented 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')?

muhammadarsal commented 7 years ago

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.

ctung commented 7 years ago

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

muhammadarsal commented 7 years ago

Can you please show the code where you're trying to change the selected options?

ctung commented 7 years ago

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); }
}
muhammadarsal commented 7 years ago

Since the problem isn't related to this thread, we should move to private conversation