【问题标题】:How to update a angular 4+ form values using console devtools?如何使用控制台开发工具更新 Angular 4+ 表单值?
【发布时间】:2017-12-11 21:28:58
【问题描述】:

我正在尝试使用控制台 (devtools) 填写 Angular 4+ 表单。

这就是我现在正在做的事情:

function fillForm(){
    let el = document.querySelector('input[ng-reflect-name="my_input"]');
    let elProbe = ng.probe(el);
    elProbe._debugContext.component.value = 'new-value';
}

我正在尝试使用的一些参考资料(如果对任何人有帮助的话):

【问题讨论】:

  • 你在哪里调用detectChanges? Angular 很懒,它想要一脚 :)
  • 同样的问题:How to do $('#someId').val(somevalue) using angular?

标签: angular


【解决方案1】:

有两种选择。第一个是使用绑定到表单的组件属性,它需要手动更改检测触发。第二个是使用与输入关联的表单控件,它不需要手动更改检测。

两者都不是更好。

对于第一个选项,请参阅@yurzui 的回答。这是第二个选项的答案 - 直接更新表单控件,无需更改检测:

function fillForm(){
    let el = document.querySelector('input[ng-reflect-name="my_input"]');
    let elProbe = ng.probe(el);

    const NgControlClassReference = elProbe.providerTokens.find((p)=>{ 
        return p.name === 'NgControl';
    });

    let directive = elProbe.injector.get(NgControlClassReference);
    let control = directive.control;

    control.setValue('some');
}

在这种情况下,您不需要更改检测,因为当您直接在控件上调用 setValue 时,它会通知 valueAccessor 有关更改:

FormControl.prototype.setValue = function (value, options) {
  ...
  this._onChange.forEach(function (changeFn) { 
      return changeFn(_this._value, options.emitViewToModelChange !== false); });

其中changeFnsetUpContorl 函数中添加的订阅者:

  control.registerOnChange((newValue: any, emitModelEvent: boolean) => {
    // control -> view
    dir.valueAccessor !.writeValue(newValue);

直接在访问器上调用writeValue,然后将值写入输入:

export class DefaultValueAccessor implements ControlValueAccessor {
  ...

  writeValue(value: any): void {
    const normalizedValue = value == null ? '' : value;
    this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', normalizedValue);
  }

您也可能会发现这篇文章很有用

Everything you need to know about debugging Angular applications

【讨论】:

  • $0 中的上下文是什么?
  • @leonardomerlin,我是elProbe,我已经更新了详细信息
  • 我选择了@yurzui 作为正确答案,因为我没有发现应该用什么参考来代替$0 参考,也没有关于幻数“3” =/ 抱歉。
  • @leonardomerlin,我的和 yurzui 的答案是不同的。我直接更新表单控件,不需要手动调用变更检测,而他的解决方案更新了父组件上的属性,需要手动触发变更检测。神奇的3 是对NgControl 类的引用。你可以选择任何你喜欢的
  • plnkr.co/edit/rvXQ4xl6TEXchueasDS5?p=preview 你确定索引是 3 吗?
【解决方案2】:

执行此操作的简单方法是使用ApplicationRef 的核心令牌运行更改检测周期

let el = document.querySelector('input[ng-reflect-name="my_input"]');
let elProbe = ng.probe(el);   
elProbe._debugContext.component.value = 'new-value';
elProbe.injector.get(ng.coreTokens.ApplicationRef).tick()

你也可以看看集成测试

https://github.com/angular/angular/blob/master/packages/forms/test/template_integration_spec.ts#L28-L30

我认为这样我们可以检查我们的组件如何与 NgModel 一起工作,并且不要在内部 NgModel 指令上调用直接 API。

在不调用变更检测的情况下我们也可以通过下面的代码来模拟用户操作

let valueAccessor = elProbe.injector.get(elProbe.providerTokens
                       .find(x =>x.name === 'DefaultValueAccessor'));

el.value = 'some';
valueAccessor.onChange('some');

但是看起来很奇怪

【讨论】:

  • 像魅力一样工作!谢谢!
  • 直接更新控件不需要变更检测
  • @Maximus Angular 以这种方式工作,所以我认为它不正确
  • @yurzui,是的,但是对于这种特殊情况,确实不需要更改检测。查看我编辑的答案
  • 你也可以看看集成测试 - 这是一个很好的参考,但测试是为了测试 ngModel - 'should support ngModel for standalone fields'formControl 是一个完美的课程。无论如何,很高兴看到表单在 html 中是如何表示的
【解决方案3】:

the accepted answer 复制/粘贴衍生产品以一次填充多个字段:

[
  { selector: "#initials", val: "JJA" },
  { selector: "#lastName", val: "Steenbruggehoek" },
  { selector: "#email", val: "john.doe@example.org" },
].forEach(item => {
    const el = document.querySelector(item.selector);
    if (!el) { console.warn(item.selector, 'not found'); return; }
    const probe = ng.probe(el);
    const ref = probe.providerTokens.find(p => p.name === 'NgControl');
    const directive = probe.injector.get(ref);
    directive.control.setValue(item.val);
});

作为另一个答案,仅适用于 debug 构建。

【讨论】:

    猜你喜欢
    • 2018-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-15
    • 2012-08-27
    相关资源
    最近更新 更多