Issue
I'm making a common autocomplete component in Angular. I'm also using Angular Material.
I am on v15, but I'm NOT using MDC, so I guess I'm using v14 material components.
I need to be able to pass mat-options into this common autocomplete component. Right now, I have this working, except for keyboard functions. The options being given to the common component are appearing in the autocomplete popup, but I can't use the arrow keys to navigate through them (like you usually can). The arrow keys only work for the options already in the common component.
Check out this working example: https://stackblitz.com/edit/57thbg?file=src%2Fapp%2Ftest-autocomplete%2Ftest-autocomplete.component.html
Is there a way to achieve this? I'm confused on why keyboard controls wouldn't be working since the DOM is rendering the mat-options being given the same as those in the common component.
Also, I cannot simply take in a string array input and use it in the template for options, because I want to be able to take in different things. For example, a mat-option could simply be:
<mat-option>Option</mat-option>
or it could be:
<mat-option [value]="row.memberName" mat-option class="custom-styling">
<span class="custom-styling">
<span class="custom-span flex-1">{{ row.memberName }}</span>
<span class="custom-span w-1000">{{ row.dob | date: "MM/dd/yyyy" }}</span>
<span class="custom-span flex-1">{{ row.memberCode }}</span>
<span class="custom-span flex-1">{{ row.businessLine }}</span>
<span class="custom-span flex-1">{{ row.businessUnit }}</span>
</span>
</mat-option>
That's why an array input won't work.
Solution
what you need is a directive + *ngTemplateOutlet
At first the directive:
@Directive({
selector: '[appTestAutocompleteOption]',
})
export class TestAutocompleteOptionDirective {
constructor(public template: TemplateRef<unknown>) {}
}
Then your autocomplete component:
@Component({
selector: 'test-autocomplete',
templateUrl: 'test-autocomplete.component.html',
})
export class TestAutocompleteComponent {
protected queryList$ = new ReplaySubject<
QueryList<TestAutocompleteOptionDirective>
>(1);
@ContentChildren(TestAutocompleteOptionDirective)
set queryListOfOptions(value: QueryList<TestAutocompleteOptionDirective>) {
this.queryList$.next(value);
}
}
You will need to use a replaysubject because the query list is available after ngContentInit
Then use this template for the autocomplete component
<mat-form-field *ngIf="queryList$ | async as queryList">
<input matInput type="search" [matAutocomplete]="autocomplete" />
<mat-icon matPrefix>search</mat-icon>
<mat-autocomplete #autocomplete="matAutocomplete">
<mat-option>start</mat-option>
<ng-container *ngFor="let option of queryList">
<mat-option>
<ng-container *ngTemplateOutlet="option.template"></ng-container>
</mat-option>
</ng-container>
<mat-option>end</mat-option>
</mat-autocomplete>
</mat-form-field>
Notice the ngFor over each element in the QueryList (which contains all Directive-Objects)
And then use it like this:
<test-autocomplete>
<ng-template appTestAutocompleteOption *ngFor="let row of [1, 2, 3]">
given option {{row +1}}
</ng-template>
</test-autocomplete>
Now you have successfully projected the content into your view.
Here is a complete example: https://stackblitz.com/edit/57thbg-rjzbcn?file=src%2Fapp%2Fautocomplete-filter-example.html
Answered By - SirOneOfMany
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.