【问题标题】:How to pass template to nested component in Angular如何将模板传递给Angular中的嵌套组件
【发布时间】:2020-04-01 08:46:17
【问题描述】:

我正在 NativeScript 和 Angular 中构建自动完成功能(这个问题也适用于纯 Angular)。

标记如下所示:

<StackLayout>
<TextField #keywords [hint]="options?.hint" [(ngModel)]="occupation"
    (textChange)="keywordsInputChange$.next(keywords.text)">
</TextField>
<ng-container *ngTemplateOutlet="parentTemplate"></ng-container>

<ScrollView orientation="vertical" height="200" *ngIf="dataItems?.length > 0" class="m-r-16 m-l-16 search-view">
    <ListView [items]="dataItems" (itemTap)="onItemTap($event)">
        <ng-template let-item="item">
            ...
        </ng-template>
    </ListView>
</ScrollView>

它将被外部使用:

<px-lookup (selected)="onOccupationSelected($event)" [options]="occupationLookupOptions">
    <ng-template let-item>
         <StackLayout class="search-item" backgroundColor="red">
               <Label [text]="item.text"></Label>
         </StackLayout>
    </ng-template>
</px-lookup>

如您所见,我想将自定义模板传递给 ListView 将使用的查找。 我正在检索这样的模板

@ContentChild(TemplateRef, { static: false }) parentTemplate: TemplateRef<any>;

我可以通过定义在查找中毫无问题地渲染它

<ng-container *ngTemplateOutlet="parentTemplate; context: { $implicit: item }"></ng-container>

但是,当我尝试将其放入也需要模板的 LietView 时,我无法使其正常工作。我收到类似 '错误:在列表模板中找不到合适的视图!嵌套级别:0' 任一项目都被渲染为 [Object object]

我已经尝试了这些选项:

<ListView [items]="dataItems" (itemTap)="onItemTap($event)">
        1. Option ===> <ng-container *ngTemplateOutlet="parentTemplate"></ng-container> -->

        2. Option ===><ng-content></ng-content>

        3. Option ===> <ng-template let-item="item"> (top template that is required by ListView)
            <ng-container *ngTemplateOutlet="parentTemplate; context: { $implicit: item }"></ng-container> (Tried to render another template with current one by passing item down the pipe)
        </ng-template>
    </ListView>

有人知道我如何实现这一点吗?

谢谢

【问题讨论】:

标签: angular nested nativescript ng-template ng-container


【解决方案1】:

关键是通过利用 TemplateRef 的依赖注入创建一个指令来存储模板的引用。

首先是指令:

// my-template.directive.ts

@Directive({ selector: '[myTemplate]' })
export class MyTemplateDirective  {
  @Input('myTemplate') type: string;

  constructor(public template: TemplateRef<any>) {}
}

(请注意,虽然type 属性没有在这个简单的案例中使用,但在使用多个嵌套模板时,它是必要的)

之后,在自动完成组件中,您使用该指令查找内容子项,如下所示:

// autocomplete.component.ts

@ContentChild(MyTemplateDirective, { static: false }) set setTemplate(value: MyTemplateDirective) {
   // for multiple templates you could implement logic using value.type

   // for example:
   // this.parentTemplates[value.type] = value.template

   this.parentTemplate = value.template;
};

在模板中

// autocomplete.component.html
// Basically your Option 3

<ListView [items]="dataItems" (itemTap)="onItemTap($event)">   
  <ng-template let-item="item">
     <ng-container *ngTemplateOutlet="parentTemplate; context: { $implicit: item }"></ng-container>
  </ng-template>
</ListView>

那么你会像这样使用它:

<px-lookup (selected)="onOccupationSelected($event)" [options]="occupationLookupOptions">
    <ng-template let-item myTemplate="pxLookupElem">
         <StackLayout class="search-item" backgroundColor="red">
               <Label [text]="item.text"></Label>
         </StackLayout>
    </ng-template>
</px-lookup>

【讨论】:

  • 你的评论是什么意思“(请注意,虽然在这种简单的情况下没有使用类型,但有多个嵌套模板是必要的)” - 我应该指定类型而不是“任何”在指令中?是否可以使用通用指令来存储任何模板?如果我想使用多个嵌套模板,或者应该提供类型 - 但如果只有一个 - 那么这样就可以了吗?
  • 还有哪里是 pxLookupElem 在 myTemplate="pxLookupElem" 中出现的?
  • 该指令允许通过myTemplate 传递字符串属性,内部称为type。这只是一个字符串,用于标识您所指的模板。由于这个自动完成组件只允许一种类型的模板(我称之为"pxLookupElem"),所以没有必要。但是,如果您想允许多个模板,您可以在@ContentChild() 的设置器中实现逻辑,然后使用单独的*ngTemplateOutlet 公开它们中的每一个。
  • 我在回答中添加了一些 cmets 以使其更清晰。希望对您有所帮助。
  • 谢谢,但您没有提到“pxLookupElem”的来源。我假设 pxLookupElem 是在模板上添加的变量,例如 - 如果那是真的,那么它不起作用我发现同样的错误:(
猜你喜欢
  • 2020-09-06
  • 1970-01-01
  • 2016-11-02
  • 1970-01-01
  • 2017-09-23
  • 2013-09-02
  • 1970-01-01
  • 2012-07-21
  • 2019-01-02
相关资源
最近更新 更多