Conditional duplicate templateref in ng-content with selector

大兔子大兔子 提交于 2019-12-20 04:48:32

问题


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?


回答1:


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

  • Dynamic template reference variable inside ngFor (Angular 2)

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.

Let's reproduce your case:

We can see that second template reference variable overrides previous.

And as result Angular handles click event on the same element:



来源:https://stackoverflow.com/questions/50073922/conditional-duplicate-templateref-in-ng-content-with-selector

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!