Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

[QUESTION] initial value with server-side lookup #129

Closed
Standaa opened this issue Mar 27, 2019 · 3 comments
Closed

[QUESTION] initial value with server-side lookup #129

Standaa opened this issue Mar 27, 2019 · 3 comments

Comments

@Standaa
Copy link

Standaa commented Mar 27, 2019

Hello,
first of all thank you for the awesome lib.
I know the question has been asked multiple times here, and I have looked at each and every question, but no matter what I do, I cannot set the initial value on the input.

Let me explain :
I am trying to have a value displaying in the input on application start, in exactly the same fashion as the 1st example of the provided Stackblitz.
However, I am using server side lookup and the async pipe. So, basically what I want to achieve is mixing example 1 and 5.

When I set the value, nothing happens. I have tried multiple different ways, to no avail.
Here is what my code looks like :

  <mat-form-field>
    <mat-select placeholder="Country of residence *" formControlName="countryCtrl" #singleSelect>
      <mat-option>
        <ngx-mat-select-search placeholderLabel="Search country..." formControlName="countryFilterCtrl" [searching]="searching"></ngx-mat-select-search>
      </mat-option>
      <mat-option *ngFor="let country of filteredCountries | async" [value]="country.name">
        {{country.name}}
      </mat-option>
    </mat-select>
  </mat-form-field>
export class Country {
  name?: string;
  code?: string;
};
this.personalInformationFormGroup = this.formBuilder.group({
     [...],
      countryCtrl: [userPersonalInformation.country, Validators.required],
      countryFilterCtrl: ['']
    });

userPersonalInformation.country is a country object that is retrieved on app load.
It can have a value if the user selected a value in the past, otherwise no value will be set.

The main difference is that I am handling search in a fully reactive way, meaning I leave the async pipe subscribing to my observable :

this.filteredCountries = this.personalInformationFormGroup.controls.countryFilterCtrl.valueChanges
      .pipe(
        takeUntil(this._onDestroy),
        debounceTime(150),
        filter(search => !!search),
        mergeMap(search => {
          return this.countryService.searchCountry(search);
        })
      );

I have read in the different questions, that setValue() should be passed an array with an index selected. This approach did not work either.
I have tried doing a very basic thing in the Stackblitz and could not get it to work either.

How can I achieve such a behaviour ?

@Standaa Standaa added the bug Something isn't working label Mar 27, 2019
@macjohnny macjohnny added not a bug question and removed bug Something isn't working labels Mar 28, 2019
@macjohnny macjohnny changed the title [QUESTION] [QUESTION] initial value with server-side lookup Mar 28, 2019
@macjohnny
Copy link
Member

@stanislasdrg for the initial value to work (and for setting any mat-select value), there must be an option with the corresponding value, otherwise the input is reset.

therefore you need to make sure that there initially exists an option with value userPersonalInformation.country. If you load that option via the async pipe, you need to set compareWith after setting the initial value, see https://github.com/bithost-gmbh/ngx-mat-select-search-example/blob/55419c3306c652851068619661e96922f7c9dd5d/src/app/examples/01-single-selection-example/single-selection-example.component.ts#L61-L75

@Standaa
Copy link
Author

Standaa commented Mar 28, 2019

Thank you for your reply.
I managed to make it work but not really as I expected.
What I gathered is that when setting data with setValue(), you need to pass one of the objects of the same array that you iterate over in your template. In my case userPersonalInformation.country was not an object of filteredCountries. Therefore it could not work (I was also missing the compareWith...).

This situation arose, because I am looking for countries using a third party API, but the user has his own country object that is retrieved from my backend. The 3rd party API I use returns a complex object, as a result I am only backing 'part' of the object on my server.

The consequence is that I will also have to write a method that uses my user's country object to find the index of the object having the same name in my filteredCountries, and return filteredCountries[index] to setValue().

Is my thinking correct here ?

Many thanks for your help. Much appreciated.

@macjohnny
Copy link
Member

I would not compare object references for equality, but rather an id, e.g. country.isoCode:

compareWith = (a: Country, b: Country) => a && b && a.isoCode === b.isoCode;

then you can have

<mat-option *ngFor="let country of countries" [value]="country">

and

setValue(userCountry)

the only thing that needs to match is the isoCode.

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

2 participants