Primeng: AutoComplete input value doesn't change when ngModel is changed programatically

Created on 10 Aug 2017  路  17Comments  路  Source: primefaces/primeng

I'm submitting a ... (check one with "x")

[x] bug report => Search github for a similar issue or PR before submitting
[ ] feature request => Please check if request is not on the roadmap already https://github.com/primefaces/primeng/wiki/Roadmap
[ ] support request => Please do not submit support request here, instead see http://forum.primefaces.org/viewforum.php?f=35

Current behavior
When a AutoComplete component is binded to a two-way variable using [(ngModel)], if you change the variable value programatically, e.g. using AJAX, the input value is not updated.

Expected behavior
The input value for the AutoComplete component should be updated when the two-way variable is updated programatically.

Please tell us about your environment:

  • Angular version: ^4.0.0

  • PrimeNG version: 4.1.2

  • Language: TypeScript~2.3.3

  • Node (for AoT issues): 6.11.1

discussion

Most helpful comment

Found a possible workaround using ReactiveForms and PrimeNG 7.1.3

To reflect FormControl changes in view it's important not to define field property.

Due to this line of code, if you define field property the component will expect to resolve the value from an object, so using patchValue with a string or a number will not reflect changes in view.
If field remains undefined AutoComplete will take the value you pass to patchValue.

The code will be:
HTML:

<p-autoComplete formControlName="name"
                [suggestions]="suggestions"
                (completeMethod)="search($event)"
                (onSelect)="setFields($event)">
  <!--display custom properties using template-->
  <ng-template let-item pTemplate="item">
    <span class="ui-autocomplete-token-label">{{item.surname}} {{item.name}}</span>
  </ng-template>
</p-autoComplete>

TS:

suggestions: { name: string; surname: string; };
formGroup: FormGroup;
list: { name: string; surname: string; } = [
  {name: 'John', surname: 'Smith'},
  {name: 'Bob', surname: 'Brown'}
];

// ...

search(ev: any) {
  // any action that filters this.list;
}

onSelect(item: any) {
  this.formGroup.get('name').patchValue(item.name);
  this.formGroup.get('surname').patchValue(item.surname);
}

All 17 comments

Additional information: I'm using the field variable since i'm receiving a complex object in the suggestions.

I'm experiencing the same effect after upgrading from 4.0.3 to 4.1.3; turns out the breaking change is with 4.1.0-rc.1. Also, the behavior only appears when using the field variable (plain text values work fine for me).

+1
I am experiencing the same issue.

+1

+1

Does it happen with 4.2.2, can't replicate with it, using showcase code;

<h3 class="first">Basic</h3>
    <p-autoComplete [(ngModel)]="country" [suggestions]="filteredCountriesSingle" (completeMethod)="filterCountrySingle($event)" field="name" [size]="30"
        placeholder="Countries" [minLength]="1"></p-autoComplete>
    <span style="margin-left:10px">Country: {{country ? country.name||country : 'none'}}</span>
    <button type="button" (click)="changeCountry()" pButton></button>

    <h3>Advanced</h3>
    <p-autoComplete [(ngModel)]="brand" [suggestions]="filteredBrands" (completeMethod)="filterBrands($event)" [size]="30"
        [minLength]="1" placeholder="Hint: type 'v' or 'f'" [dropdown]="true">
        <ng-template let-brand pTemplate="item">
            <div class="ui-helper-clearfix" style="border-bottom:1px solid #D5D5D5">
                <img src="assets/showcase/images/demo/car/{{brand}}.png" style="width:32px;display:inline-block;margin:5px 0 2px 5px"/>
                <div style="font-size:18px;float:right;margin:10px 10px 0 0">{{brand}}</div>
            </div>
        </ng-template>
    </p-autoComplete>
    <span style="margin-left:50px">Brand: {{brand||'none'}}</span>
    <button type="button" (click)="changeBrand()" pButton></button>
export class AutoCompleteDemo {

    country: any;

    countries: any[];

    filteredCountriesSingle: any[];

    filteredCountriesMultiple: any[];

    brands: string[] = ['Audi','BMW','Fiat','Ford','Honda','Jaguar','Mercedes','Renault','Volvo','VW'];

    filteredBrands: any[];

    brand: string;

    constructor(private countryService: CountryService) { }

    filterCountrySingle(event) {
        let query = event.query;        
        this.countryService.getCountries().then(countries => {
            this.filteredCountriesSingle = this.filterCountry(query, countries);
        });
    }

    filterCountryMultiple(event) {
        let query = event.query;
        this.countryService.getCountries().then(countries => {
            this.filteredCountriesMultiple = this.filterCountry(query, countries);
        });
    }

    filterCountry(query, countries: any[]):any[] {
        //in a real application, make a request to a remote url with the query and return filtered results, for demo we filter at client side
        let filtered : any[] = [];
        for(let i = 0; i < countries.length; i++) {
            let country = countries[i];
            if(country.name.toLowerCase().indexOf(query.toLowerCase()) == 0) {
                filtered.push(country);
            }
        }
        return filtered;
    }

    filterBrands(event) {
        this.filteredBrands = [];
        for(let i = 0; i < this.brands.length; i++) {
            let brand = this.brands[i];
            if(brand.toLowerCase().indexOf(event.query.toLowerCase()) == 0) {
                this.filteredBrands.push(brand);
            }
        }
    }

    changeCountry() {
        this.country = {"name": "Argentina", "code": "AR"};
    }

    changeBrand() {
        this.brand = 'BMW';
    }
}

The issue actually appears to be related almost exclusively to ChangeDetectionStrategy.OnPush and Angular's ReactiveForms, but in creating a simple test case, it appears that if you're on the latest of Angular and of PrimeNG, it works fine (as seen here: https://embed.plnkr.co/OpM96VLc8E0DmlEpdNXq/ )

If you patchValue the parent FormGroup for whatever the Autocomplete's Form Control is (i.e. in my example above this.parentFormGroup.patchValue({ brand: 'BMW' });) by directly manipulating the FormGroup, it happens 100% of the time on some combinations of Angular/PrimeNG. If you change the ChangeDetectionStrategy back to Default the Autocomplete gets the change fine (but then there's ExpressionChangedAfterItHasBeenChecked errors if you don't initialize the autocomplete after you programmatically initialize the model value that is associated with it).

I think this issue is currently resolved (but definitely something that people are going to continue to ask about until everyone upgrades to latest across the board).

As an aside, if you change AutocompleteComponent itself to be OnPush the issue still occurs (and this might be what some others are doing which is resulting in the problem).

I'm currently using an hack for this problem...

After changing the model value, i change the native element value using the @ViewChild reference.

setTimeout(() => this.autocomplete.inputEL.nativeElement.value = 'xxx');

@joao-fidalgo just curious why this ticket is closed, is the fix would be available in next release or should we be using the above hack you suggested.

Thanks

@alphaCoder i closed it since it's a non-issue for me at the moment. Also the PrimeNG team cannot replicate it and already removed it from their milestones.

Regarding your questions, i don't think they will fix anything... on the initial report i said i was using an array of complex objects as suggestions, and not a flat array like on the example @cagataycivici provided.

For now your best bet would be use the hack and create a new issue with a plunkr example.

I have Angular 5 and PrimeNG 5.2.0 and still see the same issue. The formControlName binds to plain text in this emample https://embed.plnkr.co/OpM96VLc8E0DmlEpdNXq/ and it works fine, my formControlName binds to an object, probably it is the cause.
Anybody has a workaround?

I have Angular 7.2.15 and PrimeNG 7.1.2 and I have the issue. I'm not using angular Form.
I'm using the binding to an object and using the Field.

Same as @lillyqian any workaround ?

Found a possible workaround using ReactiveForms and PrimeNG 7.1.3

To reflect FormControl changes in view it's important not to define field property.

Due to this line of code, if you define field property the component will expect to resolve the value from an object, so using patchValue with a string or a number will not reflect changes in view.
If field remains undefined AutoComplete will take the value you pass to patchValue.

The code will be:
HTML:

<p-autoComplete formControlName="name"
                [suggestions]="suggestions"
                (completeMethod)="search($event)"
                (onSelect)="setFields($event)">
  <!--display custom properties using template-->
  <ng-template let-item pTemplate="item">
    <span class="ui-autocomplete-token-label">{{item.surname}} {{item.name}}</span>
  </ng-template>
</p-autoComplete>

TS:

suggestions: { name: string; surname: string; };
formGroup: FormGroup;
list: { name: string; surname: string; } = [
  {name: 'John', surname: 'Smith'},
  {name: 'Bob', surname: 'Brown'}
];

// ...

search(ev: any) {
  // any action that filters this.list;
}

onSelect(item: any) {
  this.formGroup.get('name').patchValue(item.name);
  this.formGroup.get('surname').patchValue(item.surname);
}

still happening in angular 10 + latest primeng version

still happening in angular 10 + latest primeng version

Try using formControlName instead of ngModel, it worked for me

Still happening in angular 10 + latest primeng version, using formControlName, field and multiple.

Was this page helpful?
0 / 5 - 0 ratings