【问题标题】:Create local binding context in Angular template在 Angular 模板中创建本地绑定上下文
【发布时间】:2017-07-26 21:17:53
【问题描述】:

假设我要绑定一个深度嵌套的对象图:

<div>{{model.rootProperty}}</div>

<div>
    <div>{{model.some.deeply.nested.property.with.a.donut.name}}</div>
    <div>{{model.some.deeply.nested.property.with.a.donut.calories}}</div>
    <div>{{model.some.deeply.nested.property.with.a.donut.deliciousness}}</div>
</div>

我不想重复访问器链。我知道我可以在我的视图模型上公开一个属性,但我更喜欢某种方式来创建本地上下文。我想要的语法是这样的:

<div>{{model.rootProperty}}</div>

<div [binding-context]="model.some.deeply.nested.property.with.a.donut">
    <div>{{name}}</div>
    <div>{{calories}}</div>
    <div>{{deliciousness}}</div>
</div>

我该怎么做?

我尝试创建一个组件,其模板只包含&lt;ng-content&gt;&lt;/ng-content&gt;,但是以这种方式转置的内容仍然具有组件父组件的上下文。

我知道我可以将内部内容包装在 &lt;template&gt; 中并在我的组件中使用模板出口,但这比我更喜欢的标记,而且似乎 *ngFor 不需要这个。

这可能吗?

【问题讨论】:

  • 似乎更简单的解决方案是使用“计划 A”并将属性添加到您的视图/模型。毕竟这是它的目的。 :-)
  • 是的,但我觉得如果我的别名在模板中是明确的,它会更具可读性/可维护性。有时这种模式可以嵌套,我想在其中引用嵌套属性的一些嵌套属性,并且具有多个视图模型属性不会使关系在模板中可见。
  • 是的,您需要将 html 包装在 ng-template 中才能做到这一点

标签: angular angular2-template


【解决方案1】:

可以定义一个类似于 *ngIf 和 *ngFor 的结构指令称为 *bindingContext:

<div *bindingContext = "let  a_variable  be  an_expression">

Angular 使用这种语法在幕后做了很多魔法。首先,星号创建了一个立即使用的 。然后评估微语法并调用名为 bindingContextBe 的指令。该指令使an_expression 在模板上下文中作为$implicit 可用,而模板上下文又分配给a_variable

Angular documentation中有完整的解释。

我实现 BindingContext 如下:

import {Directive, EmbeddedViewRef, Input, 
        TemplateRef, ViewContainerRef} from '@angular/core';

@Directive({selector: '[bindingContextBe]'})
export class BindingContextDirective {
  private context = new BindingContextDirectiveContext();
  private viewRef: EmbeddedViewRef<BindingContextDirectiveContext>|null = null;

  constructor(private viewContainer: ViewContainerRef,
      private templateRef: TemplateRef<BindingContextDirectiveContext>) {
  }

  @Input()
  set bindingContextBe(context: any) {
    this.context.$implicit = context;
    if (!this.viewRef) {
      this.viewContainer.clear();
      this.viewRef = this.viewContainer.createEmbeddedView(this.templateRef,
                                                           this.context);
    }
  }
}

export class BindingContextDirectiveContext {
  public $implicit: any = null;
}

使用示例:

Full:

<div>
    <div>{{model.some.deeply.nested.property.with.a.donut.name}}</div>
    <div>{{model.some.deeply.nested.property.with.a.donut.calories}}</div>
    <div>{{model.some.deeply.nested.property.with.a.donut.deliciousness}}</div>
    <input [(ngModel)]="model.some.deeply.nested.property.with.a.donut.name">
</div>

<hr>

Alias:

<div *bindingContext="let food be model.some.deeply.nested.property.with.a.donut">
    <div>{{food.name}}</div>
    <div>{{food.calories}}</div>
    <div>{{food.deliciousness}}</div>
    <input [(ngModel)]="food.name">
</div>

PS:不要忘记在你的模块中声明directing。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-26
    • 1970-01-01
    • 2018-02-26
    • 2020-11-09
    • 1970-01-01
    • 2016-03-25
    • 1970-01-01
    相关资源
    最近更新 更多