Primeng: Autocomplete empty text when lost focus

Created on 14 Apr 2020  路  20Comments  路  Source: primefaces/primeng

If i have an object in ngModel with properties, where one property is declarated in field, if search and select with enter value from items list then when lost focus text in autocomplete will become empty. But if i select from items list with mouse click text will remain after lost focus. This issue not appear in PrimeNg version 9.0.0.

Issue

PrimeNg version : 9.0.5
Angular version : 9.1

Related past issues
https://github.com/primefaces/primeng/issues/910
https://github.com/primefaces/primeng/issues/3147

LTS-FIXED-10.0.6 LTS-FIXED-9.2.1 defect

Most helpful comment

Confirming I have the same problem. With an autocomplete set to [forceSelection]="true", here is the behavior:

  • Start typing (suggestions are displayed)
  • Down Arrow to a suggestion
  • Press ENTER to select
  • Press TAB to move focus

The last step clears the selection

Note that the following works:

  • Start typing (suggestions are displayed)
  • Down Arrow to a suggestion
  • Press TAB to select
  • Press TAB to move focus

The above steps DON'T clear the selection

All 20 comments

Same problem here.

The problem appeared in 9.0.1 version.

Same thing here...Any tips or workarounds? 9.0.6 still has the bug.

I've just noticed that this willl only happen when the forceSelection property is set to true (which on my case is required to ensure the proper selection of an existing item on the list).

Yes, only with forceSelection this happens. Please, take a look at this. With this bug we cannot use autocomplete via keyboard. Atributte forceSelection is mandatory for us, because selected item is not atomic, but object.

I have same problem, cant go back on version 9.0.0. I use improved p-Dialog.

Noticed the same problem. As some have already mentioned, this happens since v9.0.1 when you set forceSelection=true. I found that the problem has been caused by f8c37e16a7ac128daf043de92f9d1d1b6cf7d999 which tried to fix #8511.

The problem still exists in the current v9.1.0.

What happens internally in the component is this: After the overlay with the suggestions is closed, onOverlayAnimationDone() sets the suggestions list to null. The same also happens in onInput when you type too few characters. When you now tab and the input had changed, onInputChange() is called which then validates the input against the suggestions, but because there are no suggestions any more, it is considered invalid and reset.

Does anybody see a reason why the suggestion list is deleted internally in these two places? My naive fix would be to simply never delete it.

Having the same problem in v9.1.0. And I confirm it was introduced by fixing #8511. But I need this fix as well, so I can't switch back to v9.0.0.

I have 'autocomplete' component inside html form and I use the following 'autocomplete' settings:

autoHighlight: true
forceSelection: true

And then I do following steps:

  1. focus autocomplete input
  2. type any letter to display suggestions (since I use autoHighlight: true - first suggestion is highlighted/selected)
  3. press 'enter' on keyboard -> it will close suggestions and select first highlighted suggestion
  4. press 'enter' once again -> it will clear the input (and due to form validations - form isn't submitted)

But it behaves differently with the steps:

  1. focus autocomplete input
  2. type any letter to display suggestions (since I use autoHighlight: true - first suggestion is highlighted/selected)
  3. press 'tab' on keyboard -> it will close suggestions and select first highlighted suggestion
  4. focus autocomplete input again
  5. clear selected value (for instance, by pressing 'backspace')
  6. type any letter again (to see suggestions and first suggestion is highlighted)
  7. press 'enter' on keyboard -> it will close suggestions and select first highlighted suggestion
  8. press 'enter' once again -> value still will be there and form successfully submitted

@Cito - at first glance, it seems like the problem with onInputChange and suggestions is being null. And first my example shows that methods onInputChange called when we press 'enter' second time (not sure if it gets called by first 'enter' tho). But second example shows that it misses the call of onInputChange and therefore input isn't cleared.

I also don't know exact reason to set suggestions to null, but I could make some guesses: not always we have static suggestions, if we have retrieved suggestions from some REST call, next time we want to check them internally they might be already invalid; this is seems like very rare case tho, but still...I don't know exact reason here as well

@Cito - What to you think if we could come up with solution for it and create PR to fix it? I was thinking as well about 'never set suggestions to null`, but maybe there is other solution.

Also would be nice to here someone from primeng team, what's their thoughts etc...

@MaKCbIMKo Before trying to create a fix, we need proper testing, so I have started with that.

Below I posted a unit test function that should replace the currently existing test function for forceSelection in autocomplete.spec.ts. This function tests that 1) an invalid value will be removed, 2) a valid value will be kept when the overlay is still open and 3) a valid value is also kept when the overlay is already closed. The currently existing test does only 1) and does not work properly.

I can confirm that this improved test detects the problem in this issue and that my naive fix satisfies the test and does not break any other tests.

The question remains whether there is a reason why suggestions is reset in the two places. In that case, we need a different fix and add another test for that szenario where this is required.

    it('should properly implement forceSelection', fakeAsync(() => {
      autocomplete.forceSelection = true;
      fixture.detectChanges();

      const inputEl = fixture.debugElement.query(By.css('.ui-inputtext.ui-widget'));
      inputEl.nativeElement.dispatchEvent(new Event('focus'));  
      inputEl.nativeElement.focus();
      inputEl.nativeElement.click();
      flush();
      fixture.detectChanges();

      // enter valid value
      inputEl.nativeElement.value = 'VW';
      inputEl.nativeElement.dispatchEvent(new Event('input'));
      tick(autocomplete.delay);  // wait for debouncing
      fixture.detectChanges();
      tick(250); // wait for animation showing overlay
      fixture.detectChanges();
      inputEl.nativeElement.dispatchEvent(new Event('change'));
      flush();
      fixture.detectChanges();
      // value should be kept
      expect(inputEl.nativeElement.value).toEqual("VW");

      // enter invalid value
      inputEl.nativeElement.value = 'vsa';
      inputEl.nativeElement.dispatchEvent(new Event('input'));
      tick(autocomplete.delay);  // wait for debouncing
      fixture.detectChanges();
      tick(250); // wait for animation showing overlay
      fixture.detectChanges();
      inputEl.nativeElement.dispatchEvent(new Event('change'));
      flush();
      fixture.detectChanges();
      // value should be removed
      expect(inputEl.nativeElement.value).toEqual('');

      // enter valid value
      inputEl.nativeElement.value = 'VW';
      inputEl.nativeElement.dispatchEvent(new Event('input'));
      tick(autocomplete.delay);  // wait for debouncing
      fixture.detectChanges();
      tick(250); // wait for animation showing overlay
      fixture.detectChanges();
      autocomplete.onKeydown({which: 27, preventDefault(){}}); // press escape
      fixture.detectChanges();
      tick(250); // wait for animation hiding overlay
      fixture.detectChanges();
      inputEl.nativeElement.dispatchEvent(new Event('change'));
      flush();
      fixture.detectChanges();
      // value should still be kept
      expect(inputEl.nativeElement.value).toEqual("VW");
    }));

This is situation from #8511 before this bad fix. If you type "fra" and tab, string will stay in input, if you type "fra" slowly when suggestions are displayed and tab, input will be null.
https://stackblitz.com/edit/angular-8gfewa

There must be test, which detects situation on blur/change (only when forceSelection enabled):
1) before suggestions show up:

  • in this case when you type text and there is no special condition (char length for trigger) and you cause blur, it must hold blur and immediately find suggestions. If there are suggestions, text in input will be not null and then blur wont pass (you must choose) or will pass and automatically do 2) - maybe this situation could be parametrized. If there are no suggestions, text in input will be null and then blur will pass.
  • in this case when you type text and there is special condition (char length for trigger) and you cause blur, text in input will be null and then blur will pass.

2) after suggestions show up

  • in this case when you have typed text and cause blur, it must check, if text is exactly in key value (atomic, object), if yes, text will stay in input and blur will pass, otherwise text will be null and blur will pass.

Confirming I have the same problem. With an autocomplete set to [forceSelection]="true", here is the behavior:

  • Start typing (suggestions are displayed)
  • Down Arrow to a suggestion
  • Press ENTER to select
  • Press TAB to move focus

The last step clears the selection

Note that the following works:

  • Start typing (suggestions are displayed)
  • Down Arrow to a suggestion
  • Press TAB to select
  • Press TAB to move focus

The above steps DON'T clear the selection

I'm having the same issue, we can't use autocomplete with this bug so we're stuck in version 9.0.0, but also facing the need to update to version 10+ because of the changes in virtual scrolling table.

It's weird that new versions are coming along but the bug is not being fixed. I suspect that this is something bigger and not a minor fix.

I have the same problem. It's still present in version 10.0.0-rc.4.
Hope this will be fixed soon.

any update on this ?

I have exactly the same issue with prime-ng v10.0.0

For what it's worth, I'm using this override which seems to work with no ill effects that I've seen:

AutoComplete.prototype.onInputBlur = function( this: AutoComplete, event: KeyboardEvent ) {
  try {
     if( this.highlightOption ) {
       this.selectItem( this.highlightOption, false );
       this.cd.detectChanges();
     }
   } catch( e ) {
   }

  this.focus = false;
  this.onModelTouched();
  this.onBlur.emit( event );
};

For what it's worth, I'm using this override which seems to work with no ill effects that I've seen:

AutoComplete.prototype.onInputBlur = function( this: AutoComplete, event: KeyboardEvent ) {
  try {
     if( this.highlightOption ) {
       this.selectItem( this.highlightOption, false );
       this.cd.detectChanges();
     }
   } catch( e ) {
   }

  this.focus = false;
  this.onModelTouched();
  this.onBlur.emit( event );
};

Thanks for the suggestion. It actually works!

Waiting for an upstream fix...

I have the same issue. Instead of overriding onInputBlur, I override onOverlayAnimationDone:

AutoComplete.prototype.onOverlayAnimationDone = function (event: any) {
    if (event.toState === 'void') {
        //this._suggestions = null;
    }
};

The same on version 11.0.0-rc.1

The same on version 11.0.0-rc.1

Now wonder, since it has been fixed in 11.0.0-rc.2 only.

Unfortunately, my tests to avoid regression (see above) have not been added.

Was this page helpful?
0 / 5 - 0 ratings