在 Angular 模板中创建本地绑定上下文 [英] Create local binding context in Angular template

查看:28
本文介绍了在 Angular 模板中创建本地绑定上下文的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

{{model.rootProperty}}

<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>

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

{{model.rootProperty}}

<div [binding-context]="model.some.deeply.nested.property.with.a.donut"><div>{{name}}</div><div>{{卡路里}}</div><div>{{美味}}</div>

我该怎么做?

我尝试创建一个组件,其模板仅包含 <ng-content></ng-content>,但是以这种方式嵌入的内容仍然具有组件父组件的上下文.

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

这可能吗?

解决方案

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

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

Angular 中有完整的解释文档.

我实现了 BindingContext 如下:

import {Directive, EmbeddedViewRef, Input,TemplateRef, ViewContainerRef} 来自@angular/core";@Directive({选择器:'[bindingContextBe]'})导出类 BindingContextDirective {私有上下文 = 新的 BindingContextDirectiveContext();private viewRef: EmbeddedViewRef|null = null;构造函数(私有视图容器:ViewContainerRef,私有模板引用:TemplateRef) {}@输入()设置 bindingContextBe(context: any) {this.context.$implicit = context;如果(!this.viewRef){this.viewContainer.clear();this.viewRef = this.viewContainer.createEmbeddedView(this.templateRef,this.context);}}}导出类 BindingContextDirectiveContext {公共 $implicit: any = null;}

使用示例:

完整:<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 *bindingContext="让食物成为模型.some.deeply.nested.property.with.a.donut"><div>{{food.name}}</div><div>{{food.calories}}</div><div>{{food.deliciousness}}</div><input [(ngModel)]="food.name">

PS:不要忘记在你的模块中声明导演.

Say I have a deeply nested object graph I'm binding to:

<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>

I don't want to repeat that chain of accessors. I know I could expose a property on my viewmodel, but I'd prefer to some way to create a local context. My desired syntax would be something like:

<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>

How would I go about that?

I tried creating a component whose template contained only <ng-content></ng-content>, but content transcluded this way still has the context of the component's parent component.

I know I could wrap the inner content in a <template> and use a template outlet in my component, but that's more markup than I'd prefer, and it seems that *ngFor doesn't need this.

Is this possible?

解决方案

It is possible to define a structure directive similar to *ngIf and *ngFor called *bindingContext:

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

Angular does a lot of magic behind the scenes with this syntax. First of all, the asterics creates an <ng-template> which is used right away. Then the micro syntax is evaluated and a directive called bindingContextBe is called. This directive makes an_expression available as $implicit in the template context, which in turn is assigned to a_variable

There is full explanation in the Angular documentation.

I implemented BindingContext as follows:

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;
}

Usage example:

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: Don't forget to declare the directing in your module.

这篇关于在 Angular 模板中创建本地绑定上下文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆