Reputation: 2085
Suppose we have a component mat-select
<mat-form-field>
<mat-select placeholder="Hobby" name="hobby">
<mat-option *ngFor="let hobby of hobbies" [value]="hobby.value">
{{hobby.viewValue}}
</mat-option>
</mat-select>
</mat-form-field>
So for each select component we need to get select options and store them. This may be seem simple at first but what if we have 20 such select components. it will take much time and difficult to maintain which is not good approach in Agile development. Now we want to fill options from url as below:
<mat-form-field>
<mat-select placeholder="Hobby" name="hobby" srv_url=api/getHobbyOptions" ngModel>
</mat-select>
</mat-form-field>
In order to achieve this I tried many options such as created custom component and inserted between mat-select such as :
<mat-form-field>
<mat-select placeholder="Hobby" name="hobby" srv_url=api/getHobbyOptions" ngModel>
<fill-options><fill-option>
</mat-select>
</mat-form-field>
and <fill-options></fill-options>
component:
<mat-option *ngFor="let hobby of hobbies" [value]="hobby.value">
{{hobby.viewValue}}
</mat-option>
Final goal: Get srv_url from parent and load data.
Currently: just iterate over fake hobies data but even this way options are not shown in mat select.
Any other idea ? thanks in advance
Upvotes: 0
Views: 3845
Reputation: 29325
You're essentially describing a wrapper around mat-select which is a very common pattern with angular material, and the way they intend you to use it.
You'd write some component like
@Component({
selector: 'my-mat-select-wrapper',
templateUrl: './my-mat-select-wrapper.html',
})
export class MyMatSelectWrapper {
@Input() srvUrl: string;
@Input() placeholder: string;
@Input() name: string;
options$: Observable<{value: any, viewValue: string}[]>
constructor(private myApiService: MyApiService) { }
ngOnInit() {
this.options$ = this.myApiService.get(this.srvUrl);
}
}
<mat-form-field>
<mat-select [placeholder]="placeholder" [name]="name">
<mat-option *ngFor="let opt of options$ | async" [value]="opt.value">
{{opt.viewValue}}
</mat-option>
</mat-select>
</mat-form-field>
Then usage is even simpler:
<my-mat-select-wrapper placeholder="Hobby" name="hobby" srvUrl="api/getHobbyOptions"></my-mat-select-wrapper>
Now the big thing here is how to get the value? You can implement a control value accessor on the wrapper, but the much simpler option is using reactive forms and passing in the formcontrol you wnat to use as an input like:
@Component({
selector: 'my-mat-select-wrapper',
templateUrl: './my-mat-select-wrapper.html',
})
export class MyMatSelectWrapper {
@Input() fc: FormControl
@Input() srvUrl: string;
@Input() placeholder: string;
@Input() name: string;
options$: Observable<{value: any, viewValue: string}[]>
constructor(private myApiService: MyApiService) { }
ngOnInit() {
this.options$ = this.myApiService.get(this.srvUrl);
}
}
<mat-form-field>
<mat-select [placeholder]="placeholder" [name]="name" [formControl]="fc">
<mat-option *ngFor="let opt of options$ | async" [value]="opt.value">
{{opt.viewValue}}
</mat-option>
</mat-select>
</mat-form-field>
<my-mat-select-wrapper [fc]="myFormControl" placeholder="Hobby" name="hobby" srvUrl="api/getHobbyOptions"></my-mat-select-wrapper>
Upvotes: 1
Reputation: 17918
MatSelect doesn't know what srv_url
means (and neither do I). Is it a directive that you've written? Or are you simply trying to define the url as a property that mat-select uses? Either way, you haven't shown what you do with the url - that is, how you get data and what you do with it.
The simplest approach to this problem is to replace hobbies
with a function that takes the url as a parameter. The function could be part of a service as the other answer suggests, which makes it widely reusable. If you are fetching data via request, you will probably want to use the async pipe and have your function return an Observable or promise. For example:
<mat-form-field>
<mat-select placeholder="Hobby" name="hobby">
<mat-option *ngFor="let hobby of hobbiesService.getHobbies('api/getHobbyOptions') | async" [value]="hobby.value">
{{hobby.viewValue}}
</mat-option>
</mat-select>
</mat-form-field>
Service code:
@Injectable()
export class HobbiesService {
getHobbies(url): Observable<any[]> {
if (url) {
return ... // fetch data from url and return Observable;
}
}
}
You will need to inject the service into any application component that uses it.
constructor(public hobbiesService: HobbiesService) {}
Upvotes: 1
Reputation: 3502
You can create a service
to fetch data and load it in the variable in .ts
and bind
that variable in HTML.
Reference Component HTML
<mat-form-field>
<mat-select placeholder="Hobby" name="hobby" [(ngModel)]="selectedValue">
<mat-option *ngFor="let hobby of hobbies" [value]="hobby.value">
{{hobby.viewValue}}
</mat-option>
</mat-select>
</mat-form-field>
<p> Selected value: {{selectedValue}} </p>
Component script
@Component({
selector: 'select-form-example',
templateUrl: './select-form-example.html',
})
export class SelectFormExample {
hobbies = [
{value: 'cricket-0', viewValue: 'Cricket '},
{value: 'football-1', viewValue: 'Football'},
{value: 'books-2', viewValue: 'Books'}
];
// setting this is the key to initial select.
selectedValue: string = this.hobbies[0].value;
}
Upvotes: 0