我有以下模板:

<div>
  <span>{{aVariable}}</span>
</div>

并希望以:

<div "let a = aVariable">
  <span>{{a}}</span>
</div>

有办法吗?


当前回答

更新3

问题https://github.com/angular/angular/issues/2451在Angular 4.0.0中已修复

另请参阅

https://github.com/angular/angular/pull/13297 https://github.com/angular/angular/commit/b4db73d https://github.com/angular/angular/issues/13061

更新2

这是不支持的。

有模板变量,但不支持分配任意值。它们只能用于引用它们应用的元素,导出指令或组件的名称,以及ngFor等结构指令的作用域变量,

参见https://github.com/angular/angular/issues/2451

更新1

@Directive({
  selector: '[var]',
  exportAs: 'var'
})
class VarDirective {
  @Input() var:any;
}

然后像这样初始化

<div #aVariable="var" var="abc"></div>

or

<div #aVariable="var" [var]="'abc'"></div>

然后用这个变量

<div>{{aVariable.var}}</div>

(未测试)

# variable创建对VarDirective的引用(exportAs: 'var') var="abc"实例化VarDirective,并将字符串值"abc"传递给它的值输入。 aVariable。Var读取分配给Var指令Var输入的值。

其他回答

我试图做一些类似的事情,看起来这个问题已经在angular的新版本中得到了解决。

    <div *ngIf="things.car; let car">
      Nice {{ car }}!
    </div>
    <!-- Nice Honda! -->

更新

我们可以创建像*ngIf这样的指令,并将其命名为*ngVar

ng-var.directive.ts

@Directive({
    selector: '[ngVar]',
})
export class VarDirective {
    @Input()
    set ngVar(context: unknown) {
        this.context.$implicit = this.context.ngVar = context;

        if (!this.hasView) {
            this.vcRef.createEmbeddedView(this.templateRef, this.context);
            this.hasView = true;
        }
    }

    private context: {
        $implicit: unknown;
        ngVar: unknown;
    } = {
        $implicit: null,
        ngVar: null,
    };

    private hasView: boolean = false;

    constructor(
        private templateRef: TemplateRef<any>,
        private vcRef: ViewContainerRef
    ) {}
}

对于这个*ngVar指令,我们可以使用以下方法

<div *ngVar="false as variable">
      <span>{{variable | json}}</span>
</div>

or

<div *ngVar="false; let variable">
    <span>{{variable | json}}</span>
</div>

or

<div *ngVar="45 as variable">
    <span>{{variable | json}}</span>
</div>

or

<div *ngVar="{ x: 4 } as variable">
    <span>{{variable | json}}</span>
</div>

Angular4 ngVar

另请参阅

Angular 4在哪里为*ngIf定义了“as local-var”行为?

原来的答案

角v4

div + ngIf + let {{variable.a}} {{variable.b}} div + ngIf + as

view

<div *ngIf="{ a: 1, b: 2, c: 3 + x } as variable">
  <span>{{variable.a}}</span>
  <span>{{variable.b}}</span>
  <span>{{variable.c}}</span>
</div>

component.ts

export class AppComponent {
  x = 5;
}

如果你不想创建像div这样的包装器,你可以使用ng-container

view

<ng-container *ngIf="{ a: 1, b: 2, c: 3 + x } as variable">
  <span>{{variable.a}}</span>
  <span>{{variable.b}}</span>
  <span>{{variable.c}}</span>
</ng-container>

正如@Keith在评论中提到的

这将在大多数情况下工作,但它不是一个普遍的解决方案,因为它 依赖于变量为真

有关另一种方法,请参阅update。

我的建议是:https://medium.com/@AustinMatherne/ angular-let-direcy-a168d4248138

这个指令允许你这样写:

<div *ngLet="'myVal' as myVar">
  <span> {{ myVar }} </span>
</div>

我喜欢创建一个指令来做这件事的方法(很好的调用@yurzui)。

最后我在Medium上找到了一篇文章,Angular的“let”指令很好地解释了这个问题,并提出了一个自定义的let指令,它在我的用例中工作得很好,代码更改很少。

以下是要点(在发布时)和我的修改:

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

interface LetContext <T> {
  appLet: T | null
}

@Directive({
  selector: '[appLet]',
})
export class LetDirective <T> {
  private _context: LetContext <T> = { appLet: null }

  constructor(_viewContainer: ViewContainerRef, _templateRef: TemplateRef <LetContext <T> >) {
    _viewContainer.createEmbeddedView(_templateRef, this._context)
  }

  @Input()
  set appLet(value: T) {
    this._context.appLet = value
  }
}

我的主要改变是:

将前缀从'ng'更改为'app'(你应该使用你的应用程序的自定义前缀是什么) 将appLet: T更改为appLet: T | null

不知道为什么Angular团队还没有发布一个官方的ngLet指令。

原始源代码归功于@AustinMatherne

我是https://www.npmjs.com/package/ng-let的作者

将数据作为局部变量共享到html组件模板的结构指令。

源代码:

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

interface NgLetContext<T> {
    ngLet: T;
    $implicit: T;
}

@Directive({
    // tslint:disable-next-line: directive-selector
    selector: '[ngLet]'
})
export class NgLetDirective<T> {

    private context: NgLetContext<T | null> = { ngLet: null, $implicit: null };
    private hasView: boolean = false;

    // eslint-disable-next-line no-unused-vars
    constructor(private viewContainer: ViewContainerRef, private templateRef: TemplateRef<NgLetContext<T>>) { }

    @Input()
    set ngLet(value: T) {
        this.context.$implicit = this.context.ngLet = value;
        if (!this.hasView) {
            this.viewContainer.createEmbeddedView(this.templateRef, this.context);
            this.hasView = true;
        }
    }

    /** @internal */
    public static ngLetUseIfTypeGuard: void;

    /**
     * Assert the correct type of the expression bound to the `NgLet` input within the template.
     *
     * The presence of this static field is a signal to the Ivy template type check compiler that
     * when the `NgLet` structural directive renders its template, the type of the expression bound
     * to `NgLet` should be narrowed in some way. For `NgLet`, the binding expression itself is used to
     * narrow its type, which allows the strictNullChecks feature of TypeScript to work with `NgLet`.
     */
    static ngTemplateGuard_ngLet: 'binding';

    /**
     * Asserts the correct type of the context for the template that `NgLet` will render.
     *
     * The presence of this method is a signal to the Ivy template type-check compiler that the
     * `NgLet` structural directive renders its template with a specific context type.
     */
    static ngTemplateContextGuard<T>(dir: NgLetDirective<T>, ctx: any): ctx is NgLetContext<Exclude<T, false | 0 | '' | null | undefined>> {
        return true;
    }
}

用法:

import { Component } from '@angular/core';
import { defer, Observable, timer } from 'rxjs';

@Component({
  selector: 'app-root',
  template: `
  <ng-container *ngLet="timer$ | async as time"> <!-- single subscription -->
    <div>
      1: {{ time }}
    </div>
    <div>
      2: {{ time }}
    </div>
  </ng-container>
  `,
})
export class AppComponent {
  timer$: Observable<number> = defer(() => timer(3000, 1000));
}