valor-software / ng2-select

Angular based replacement for select boxes
http://valor-software.github.io/ng2-select/
MIT License
675 stars 587 forks source link

Remote call: Items array doesn't update the view #929

Open dave0688 opened 6 years ago

dave0688 commented 6 years ago

I have an issue with ng2-select and remote calls: When I type something, my service fetches new items according to the search string. The [items] array is getting updated properly, however the ui is not showing the updated list. Instead, it disappears. Then, when I focusout, the dropdown shows the correct options.

Please see my template here:

    <ng-select
      #select 
      [allowClear]="'true'"
      id="DropdownTypeaheadQuestion-{{ question.id }}"
      [(items)]="items"
      [formControl]="formControlToUse"
      placeholder="{{ placeholderText }}"
      [multiple]="isMultiple"
      (selected)="execSelected($event)"
      (typed)="execKeypress($event)">
    </ng-select>
    <i class="fa fa-spinner fa-pulse fa-3x fa-fw font-size-160 loading-icon" *ngIf="loadingResults"></i>

Here's the controller (relevant methods only):

  execKeypress($event) {
    // When remote, clear all items directly on keypress. Else we have an ugly lag because of the debounce time.
    if (this.config.remote === true) {
      this.items = [];
    }
    this.searchSubject.next($event);
  }
// Inside ngOnInit I subscribe to the observable
    this.searchSubject.debounceTime(500)
                      .takeUntil(this.ngUnsubscribe)
                      .subscribe( (searchTextValue: string) => {

      // save search string on scope
      this.searchTextValue = searchTextValue;
      this.config.httpParams = this.config.httpParams.set('search', searchTextValue);

      // only send search if more than x chars (or empty)
      if (searchTextValue === '' || searchTextValue.length >= this.config.minChars) {
        this.fetchResults();
      }
    });
// fetchResult method fetches the new items and appends them to the items array
this.httpClient.get(url, {params: this.config.httpParams})
                   .takeUntil(this.ngUnsubscribe)
                   .subscribe( (res: any) => {

                     this.items = this.transformSelectableValuesToConsumables(res);

                     this.select.items = this.items;

                     this.loadingResults = false;
                   },
                   (error) => {
                     this.loadingResults = false;

                     // TODO: Implement proper error handling
                   });

I see that the items array is properly filled, but it's not getting refreshed in the UI. Any help is greatly appreciated! :)

shayl29 commented 6 years ago

As far as I know, items property cannot be two-way binding but maybe i'm mistaken. I would replace the [(items)] into [items]. Also i suggest you return the http call as observable to your component and subscribe it from there.

optimistex commented 6 years ago

Hi. It was fixed in that fork: https://github.com/optimistex/ng2-select-ex The fork supported with lazy loading of items. Look at this: https://github.com/optimistex/ng2-select-ex/blob/ce8b464dcfdf7e0a1d01b7bb0d2e8660576e31a9/src/ngx-select/ngx-select.component.spec.ts#L808-L839

If you will need more examples text me. I have similar functionality in my different project.

mrmercc commented 5 years ago

Hi @dave0688,

I've encountered same problem with my app and didn't wanted to change plugin. So after some research and readings I solved it like this;

// service

`/**

// component.ts

`searchCustomer(event, customerType, supplierType: null | string = '') { const customerName = event.term; this.customerService.customerSearch(customerType, customerName).subscribe((data) => { // this.insuranceCustomerData = data.body;

  if (customerType === 'SUPPLIER' && supplierType !== null) {

    if (supplierType === 'transport') {
      this.transportCustomerData = data.body;
    } else if (supplierType === 'insurance') {
      this.insuranceCustomerData = data.body;
    }

  }

});

}`

// template.html

`

                  <div class="col-sm-8">
                    <ng-select placeholder="Müşteri arama..." [items]="insuranceCustomerData" bindLabel="firmName"
                      bindValue="id" (search)="searchCustomer($event, 'SUPPLIER', 'insurance')">
                    </ng-select>
                  </div>
                </div>`

and see the result (before search, no inital data)

image

after key press search;

image

hope it works for you too ! :)