0

I'm trying to re-populate an input that uses a mat-autocomplete. However, whenever I send the value with this.optionForm.patchValue({selectedOption: 'my value'}) the results don't show in the GUI. If I console.log() I can clearly see the value is set. I'm not sure if the issue has to do with the fact that I'm sometimes setting an object into the field and other times setting just a string? But I would like to be able to re-populate the input with results and display it appropriately. No matter how I try I can't seem to get the results to display.

Below is my component cut down to just the input in question and my Observable that is fetching results for the mat-autocomplete. These work fine the first time the form is used.

// component.html
<mat-form-field>
<mat-label>Option Object</mat-label>
<input type="text" matInput formControlName="selectedOption" required
       [matAutocomplete]="autoGroup">
<mat-autocomplete #autoGroup="matAutocomplete"
                  (optionSelected)="updateOptionInfo($event.option.value)"
                  [displayWith]="displayFn">
    <mat-option *ngFor="let result of resultOptions | async" [value]="result">
        <span>{{result}}</span>
    </mat-option>
</mat-autocomplete>

// component.ts
this.resultOptions = this.optionForm.get('selectedOption').valueChanges
        .pipe(
            debounceTime(300),
            switchMap(value => {
                if (value === '') {
                    this.clearProviderInfo();
                    return of(null);
                }
                if (value !== '' && ((typeof value) !== 'object')) {
                    return this.optionService.fetchAndFilterOptions(value)
                        .pipe(
                            catchError((e) => {
                                console.error(e);
                                return of([]); // empty list on error
                            })
                        );
                } else {
                    return of(null);
                }
            })
        );

Any help would be appreciated!

SortingHat
  • 727
  • 3
  • 15
  • 30

2 Answers2

3

I've created a stackblitz to reproduce the issue:

https://stackblitz.com/edit/material-6-gh3rmt?file=app/app.component.ts

In doing so I realize what the issue was! By having a display function returning some property of the object, it obviously displays empty for a string. So the object is being set and can be seen in the form, but because I've used a custom display function it is run over by the null property on the string.

Hopefully I can help other people that may run into this issue in the future!

To flesh out this solution:

  displayFn(x) {
    return x.name; // if name doesn't exist this will obviously return null!
  }

So a fix is to have a backup in the case that what is being selected isn't an object with the .name property:

if ((typeof x) === 'string') {
    return x;
}
return x ? x.name : undefined;
SortingHat
  • 727
  • 3
  • 15
  • 30
  • Excellent... We can all learn that recreating a minimal, verifiable example often makes the core issue come to the surface, which makes resolution easier :) – Akber Iqbal Feb 13 '19 at 05:34
  • @daswolle, thanks for providing the stackblitz, but it should be in the updated question and should not be posted as an answer as its not a solution but a question extension. Thank you. And please see my answer, and comment issues, so that we can remove issues to fix the solution. – Abhishek Kumar Feb 13 '19 at 06:22
  • 1
    @AbhishekKumar you're right the stackblitz currently does not represent a solution. I'll update this post to be more specifically address the issue as presented. – SortingHat Feb 20 '19 at 23:31
  • @daswolle thanks for making this an answer for the question, it will be helpful for others. – Abhishek Kumar Feb 21 '19 at 02:47
2

Approach 1:
Use setTimeout to achieve the desired result, use as following -

setTimeout(()=>{
      this.optionForm.patchValue({selectedOption: 'test'});
}, 0);

Approach 2 :
This approach works without async

    //-----in component.html file, without async-------
        *ngFor="let result of resultOptions"


   // -------in component.ts file---------
    this.optionForm.get('selectedOption').valueChanges
        .pipe(
            debounceTime(300),
            switchMap(value => {
                if (value === '') {
                    this.clearInfo();
                    return of(null);
                }
                if (value !== '' && ((typeof value) !== 'object')) {
                    return of(this.pretendOptions);
                } else {
                    return of(null);
                }
            })
        ).subscribe(e=>this.resultOptions = e);

        //--- value is updated after subscribing to the `valueChanges`.    
        this.optionForm.patchValue({selectedOption: 'test'}); 

Demo without async operator

Abhishek Kumar
  • 2,501
  • 10
  • 25
  • Thanks for the proposed solution; however, this is not the issue. The issue as described in my other response is that the display function returns null for a property that doesn't exist. – SortingHat Feb 20 '19 at 23:32
  • @daswolle from the question, and stackblitz it was assumed that the options were not displayed in the select box after updating the observable array, so i answered the question accordingly. But its fine, if the issue has been resolved. – Abhishek Kumar Feb 21 '19 at 02:49
  • Yes, thank you @abhishek, I appreciate the input. The questions and feedback helped clarify everything! – SortingHat Mar 04 '19 at 19:59