I have a component which toggles the component's template based on client device size. Component code is:
import {Component} from '@angular/core';
import {BreakpointObserver, Breakpoints} from '@angular/cdk/layout';
@Component({
selector: 'ui-switcher',
template: `
<ng-content *ngIf="isSmall" select="mobile"></ng-content>
<ng-content *ngIf="!isSmall" select="web"></ng-content>
`
})
export class UiSwitcherComponent {
public isSmall: boolean;
constructor(breakpointObserver: BreakpointObserver) {
breakpointObserver.observe([Breakpoints.Small, Breakpoints.XSmall]).subscribe(result => {
this.isSmall = result.matches;
});
}
}
I use it like this:
<ui-switcher>
<web>
<!-- some commented details -->
<input class="form-control mr-2" #searchInput
type="text" (keyup)="this.search(searchInput.value)">
</web>
<mobile>
<!-- some commented details -->
<input class="form-control" #searchInput
type="text" (keyup)="this.search(searchInput.value)">
</mobile>
</ui-switcher>
In the mobile size, everything works correctly but in desktop size the value passed to search(value)
function is always an empty string.
When I debug the app, it seems that #searchInput
templateref is not working correctly (value of the element it refers to is always empty).
Why templateref doesn't work correctly?
In angular template reference variables should be unique per view.
Views can be two types View and EmbeddedView. Templates, that we write within structural directives(inside ng-template
tag or *ngFor
), represent embedded views. This way we can have the same name of template reference variable in different ng-templates.
For an example see
Let's imagine we have AppComponent
and wrote in template:
<ui-switcher>
<web>
<!-- some commented details -->
<input class="form-control mr-2" #searchInput
type="text" (keyup)="this.search(searchInput.value)">
</web>
<mobile>
<!-- some commented details -->
<input class="form-control" #searchInput
type="text" (keyup)="this.search(searchInput.value)">
</mobile>
</ui-switcher>
Angular treats it as one AppComponentView because there is no any structural directives in this template. Both inputs belong to the same view.
Now when Angular compiler parses this template it creates one ViewBuilder per view with refNodeIndices property:
private refNodeIndices: {[refName: string]: number} = Object.create(null);
that holds all references in current template.
We can see that second template reference variable overrides previous.
And as result Angular handles click event on the same element: