Angular 2子组件未正确检测到更改

时间:2016-10-18 05:32:07

标签: angular typescript

Plunker的一个例子: https://plnkr.co/edit/aWUE54EUMIm8rnw3PZOO?p=preview

第一个按钮递增值。如果该值小于10,则应启用该按钮,否则应禁用该按钮。 第二个按钮将值重置为0.

this.button1 = new ButtonAction(
  "info",
  "check",
  "right",
  "Click me!",
  "medium",
  true,
  true,
  new Command(
    () => this.val += 1,
    () => {
      return this.val < 10;
    }
  ),
  false
);

this.button2 = new ButtonAction(
  "info",
  "check",
  "right",
  "Reset first button!",
  "medium",
  true,
  true,
  new Command(
    () => this.val = 0,
    null
  ),
  false
);

当值达到10时,第一个按钮确实会自行禁用,但是当我将值重置为0时,即使输出中的所有内容都正常,它也不会更新:

Marked for check with value 7
btnClass: btn btn-outline-info btn-block
isDisabled: false
Marked for check with value 8
btnClass: btn btn-outline-info btn-block
isDisabled: false
Marked for check with value 9
btnClass: btn btn-outline-info btn-block
isDisabled: false
Marked for check with value 10
btnClass: btn btn-outline-info btn-block disabled
isDisabled: true
Marked for check with value 0
btnClass: btn btn-outline-info btn-block
isDisabled: false

这是设置值的方式:

set val(v: number){
  this._val = v;
  console.log("Marked for check with value "+this._val);
  //this.cd.markForCheck();
  this.cd.detectChanges();
}

markForCheck也不起作用所以我真的不知道该做什么,除了通过ElementRef自己处理DOM(已经尝试过它并且它有效),但我真的不想这样做=)

我一直在尝试检测问题,我想生成的工厂类将buttonClasses的先前值与当前值进行比较,当它从btn btn-outline-info btn-block转到btn btn-outline-info btn-block disabled时它会起作用,但不是相反的方式周围。

图片显示了当我使用第二个按钮重置值并且buttonClasses在第一次调用之后第一次调用时会发生什么。 Debugging after reset button click

self._expr_2是之前的值,它是btn btn-outline-info btn-block但它也应该有disabled。当前值没有disabled类,这是正确的。

提前感谢您的帮助。我真的不知道该怎么做......

1 个答案:

答案 0 :(得分:2)

使用ChangeDetectionStrategy.OnPush策略,您必须调用cd.markForCheck API方法。

最重要的是:

  

它标记了从我们的组件到root的路径,以便检查   下次更改检测运行。

因此,您需要在UIButton ChangeDetectorRefs点击它,否则更改检测仅在您执行操作后的一个按钮上有效。

每当angular2更改检测时,它会在更改后将视图标记为已检查。 enter image description here

以下是angular2处理点击事件的方式:

<强> UIButton.ngfactory.js

_View_UIButton0.prototype._handle_click_1_0 = function($event) {
  var self = this;
  self.markPathToRootAsCheckOnce();
  self.debug(1,3,14);
  var pd_0 = (self.context.clicked() !== false);
  return (true && pd_0);
};

注意:

self.markPathToRootAsCheckOnce();

它标记当前要检查的按钮,但第二个按钮将保持ChangeDetectorStatus.Checked状态,并在检查时省略。

所以你的解决方案可能如下所示:

1)UIButton组件

constructor(public cd: ChangeDetectorRef) {}

2)应用程序组件

@ViewChildren(UIButton) buttons: QueryList<UIButton>;

set val(v: number){
  this._val = v;
  console.log("Marked for check!");
  this.buttons.toArray().forEach(btn => btn.cd.markForCheck());
}

这样两个按钮都会被检查

在行动中查看 Plunker

希望这能帮到你!