46

在 Angular 1 中,我们可以通过这种方式进行一次绑定:{{ ::myFunction() }}.

在角度 2 中,这是抛出:

EXCEPTION: Template parse errors:
Parser Error: Unexpected token : at column 2 in [{{ ::consent(false, undefined, box) }}] in CookieConsent@5:29 ("ull-right" href="" (click)="consent(true, $event, box)">De acuerdo</a>
        <span class="hidden">[ERROR ->]{{ ::consent(false, undefined, box) }}</span>

我们如何在 angular2 中进行一次绑定?

4

7 回答 7

19

我在这里找到了一次在 Angular 2 中绑定的解决方案: https ://github.com/angular/angular/issues/14033

我创建了这个指令:

 import { Directive, TemplateRef, ViewContainerRef, NgZone } from "@angular/core";

@Directive({
    selector: '[oneTime]',
})
export class OneTimeDirective {
    constructor(template: TemplateRef<any>, container: ViewContainerRef, zone: NgZone) {
        zone.runOutsideAngular(() => {
            const view = container.createEmbeddedView(template);
            setTimeout(() => view.detach());
        })
    }
}

并使用它:

  <some-selector *oneTime [somePropertyToOneTimeBinding]="someValueToOneTimeBinding"></some-selector>

例如:

     <iframe *oneTime [src]="myUrl"></iframe>
于 2017-12-18T18:54:13.780 回答
15

ChangeDetectionStrategy.CheckOnce是这个问题的解决方案。

这里的一些信息:

于 2016-06-05T11:50:26.150 回答
5

目前,您无法使用 Angular 2 进行一次绑定。但是,您可以知道绑定何时更改并重置您的输入。

Angular 2 提供了相同的 OnChanges 生命周期钩子。您需要实现 OnChanges 接口以获取更改。

请参阅下面的代码示例,当调用 OnInit 时,我将数据绑定属性存储在私有变量中。

export class Footer implements OnInit, OnChanges {
  @Input() public name: string;
  private privname: string;

  constructor() { }

  ngOnInit() {
    this.privname = this.name;
  }


  ngOnChanges(changes: { [key: string]: SimpleChange }): void {
    if (!changes["name"].isFirstChange()) {
        this.name = this.privname;
    }
  }
}

稍后当发生其他更改时,我将在后续更改中将该值设置为其旧值。

这种机制的工作方式类似于一次性绑定

替代解决方案:您还可以使用 setter 函数来捕获更改。

于 2016-02-18T03:31:05.580 回答
3

利用ngOnInit()

在 Angular 2+ 中,我们ngOnInit()通常只运行一次,恰好在组件初始化的时候。这是一次性绑定问题的最简单且通常最好的解决方案。

绑定到一个函数可能会导致对该函数进行数十次不必要的调用,并降低您的应用程序的速度。

而不是{{ ::myFunction() }},在组件上创建一个属性并将其值设置为ngOnInit()

export class MyComponent implements OnInit {
  myValue: any;

  constructor() { }

  ngOnInit() {

    this.myValue = /* CALL FUNCTIONS OR CALCULATE VALUE HERE */

  }
}

然后在模板中,只需使用:

 {{ myValue }} 

您的计算将只运行一次。

于 2020-11-16T19:23:38.090 回答
3

ChangeDetectionStrategy.CheckOnce 是这个问题的解决方案。

这已更新以OnPush查看代码中的注释:

export declare enum ChangeDetectionStrategy {
    /**
     * `OnPush` means that the change detector's mode will be set to `CheckOnce` during hydration.
     */
    OnPush = 0,
    /**
     * `Default` means that the change detector's mode will be set to `CheckAlways` during hydration.
     */
    Default = 1,
}
于 2017-06-07T09:08:43.803 回答
0

由于默认情况下不可能在 Angular 中进行一次读取/绑定,我认为编写一个公共 getter 函数将解决这个问题。

例如

public getValue():number {
 return mynumber ? mynumber : 25; // if mynumber is not undefined the mynumber else return 25
}

//In html template
<input type="range" min="getValue()" max="100">

如果 getter 函数能够在模板渲染发生之前回复,这将完美地工作。所以如果在 ngOnInit() 函数中完成 mynumber 的初始化会很棒

于 2018-12-05T13:36:50.323 回答
0

Angular 不提供任何语法糖来控制输入的绑定频率。

但是,您可以控制输入更新时的反应时间。有两种方法,其中一种或两种都可用于获得所需的行为:

  1. Input使用setter并有条件地将更新转发到组件主体或组件的模板。
  2. 在满足输入时打开关闭组件中的更改检测ChangeDetectorRef

请注意,关闭更改检测并不意味着不会更新输入。输入将始终更新,因此ngOnChanges无论更改检测是关闭还是打开都会被调用。但是,如果更改检测关闭,模板将不会针对更新的输入进行更新。请参阅代码框以了解此效果。

示例 1

为了解释上面的第 1 点,请考虑以下几点:

  _input1: number;
  @Input() set input1(input: number) {
    if (this._input1 === undefined || this._input1 === null) {
      this._input1 = input;
    }
  }

在模板中消费

  <div>Bound Input1: {{ _input1 }}</div>

_input1是组件的本地副本,仅在需要时更新,即在上述特定情况下,本地副本仅在之前为nullundefined时更新。input1是输入属性。这里我们假设一个未定义值永远不会被认为是一个有效值,除非input1传递一个非空 非未定义值,否则我们将认为“绑定一次”没有发生。

示例 2

ChangeDetectorRef文档摘录:

提供变更检测功能的基类。更改检测树收集要检查更改的所有视图。使用这些方法从树中添加和删除视图,启动更改检测......

所以 ChangeDetectorRef 的方法detach可以用来从变化检测树中分离一个组件。为了演示上面的第 2 点,以下示例等待所有输入都满足,然后关闭更改检测:

import {
  ChangeDetectorRef,
  Component,
  Input,
  OnChanges,
  SimpleChanges
} from "@angular/core";

@Component({
  selector: "bind-until-all",
  template: `
    <div>Input1: {{ input1 }}</div>
    <div>Input2: {{ input2 }}</div>
    <div>Input3: {{ input3 }}</div>
  `
})
export class BindUntillAllComponent implements OnChanges {
  /**
   * We assume that a null or undefined value is not an empty.
   * And until a non-empty value is passed to an input, it'll be considered as not-assigned.
   *
   * Based on the use case, define what is a suitable "empty" value
   * and assign that value as the default value to the inputs.
   */
  @Input() input1: number;
  @Input() input2: number;
  @Input() input3: number;

  private isDetached: boolean = false;

  constructor(private cdr: ChangeDetectorRef) {}

  ngOnChanges(changes: SimpleChanges) {
    // Check whether all inputs are satisfied i.e. they have non-empty values assigned
    // For our case, type === "number" satisfies that the value is non-empty
    const areAllInputsSatisfied = [this.input1, this.input2, this.input3].every(
      (n) => typeof n === "number"
    );

    // Stop change detection after triggering the manual change detection once
    if (areAllInputsSatisfied && !this.isDetached) {
      this.cdr.detectChanges();
      this.cdr.detach();

      this.isDetached = true;
    }
  }
}

上面提到的代码框中的实时示例

于 2021-04-08T14:21:35.473 回答