通过编程更新Angular 2字段

7
我有一个表单字段,它运行良好。也就是说,当我输入、粘贴等操作时,fooObj.expDate会实时更新并进行验证。我使用了pre标签以便更加清晰明了。
  <pre>{{fooObj.someDate | json}}</pre>

  <div class="form-group inline-form__input">
    <label for="someDate">Some Date</label>
    <input tabindex="2"
           type="tel"
           class="form-control"
           maxlength="7"
           placeholder="MM/YY"
           formControlName="someDate"
           name="someDate"
           [(ngModel)]="fooObj.someDate"
           someDate>
  </div>

然而,我在这个字段上使用了someDate指令。该指令拦截粘贴事件,取消粘贴事件,对输入进行一些花式格式化,然后执行以下操作:
setTimeout(() => {
  this.target.value = 'lol fancy date';
}, 3000);

target.value 是我的 someDate 字段。在输入框内,该值可以更新(我可以看到屏幕上的变化)。然而,fooObj.someDate 没有被更新,也没有发生验证。例如,在超时中设置目标值不会触发与键入/粘贴/任何其他 JavaScript 事件相同的验证/对象更新。

Angular 文档 对此没有太多有用的说法:

Angular 仅在应用程序对异步事件(例如按键)做出响应时更新绑定(因此更新屏幕)。此示例代码将 keyup 事件绑定到数字 0,这是可能的最短模板语句。虽然该语句没有任何有用的功能,但它满足 Angular 的要求,以便 Angular 将更新屏幕。

那么,我如何从指令触发字段的更新?

编辑:我尝试按照评论中的建议在元素上触发事件,使用此处找到的代码在我的元素上:如何手动触发 onchange 事件?

运行正常,但不强制更新字段:

  if ("createEvent" in document) {
    var evt = document.createEvent("HTMLEvents");
    evt.initEvent("change", false, true);
    this.target.dispatchEvent(evt);
  }
  else
    this.target.fireEvent("onchange");

另外,这就是我认为合成事件不会触发“正常”操作(如按下键或其他操作)的原因(我真的希望我理解有误或他们在这种情况下是错误的,但尝试重新发出粘贴事件时它并没有起作用):https://www.w3.org/TR/clipboard-apis/#clipboard-event-interfaces

注意: 合成事件没有默认操作。换句话说,虽然上面的脚本将触发粘贴事件,但数据实际上不会被粘贴到文档中。


你尝试触发它的“input”事件了吗? - Meir
@Meir:我之前尝试重新触发了一次粘贴事件。我被告知这样会创建一个“合成”事件,不能像正常的onClick / paste / keyup / whatever触发。 (http://stackoverflow.com/questions/40848003/set-preventdefault-back-to-false-on-javascript-event)。我将尝试onChange()并只发出普通的keyUp事件。 - VSO
也尝试使用“input”事件。 - Meir
@Meir:您能详细说明一下吗?比如像“this.target.fireEvent("input");”这样的内容?我也尝试过像这里第一个答案中所示的生成按键事件:https://dev59.com/FXRB5IYBdhLWcg3wiHpl。但两种方法都没有成功,如果您有其他想法,请告诉我,非常感谢您的帮助。 - VSO
this.target.dispatchEvent(new Event('input')): - Meir
1个回答

3

我不清楚您的指令细节,但我可以猜测您的意图。首先,我们将订阅控件的valueChanges可观察对象,并放弃直接在控件上进行双向绑定,以避免过多的写入和检查:

form.html

<input tabindex="2"
             type="tel"
             class="form-control"
             maxlength="7"
             placeholder="MM/YY"
             formControlName="someDate"
             name="someDate"
             someDate />

form.ts

这里是我们订阅的地方(它可以移出构造函数,具体取决于您何时创建表单)。

constructor() {
    this.myForm = new FormGroup({
        someDate: new FormControl(''),
    });

    this.myForm.controls['someDate'].valueChanges.subscribe(
      value => this.fooObj.someDate = value;
      );
  }

some-date.directive.ts

这个指令会将值写入控件,并订阅valueChanges,然后更新我们的模型。这适用于粘贴事件和所有其他事件(所以你可以限制目标事件,但我至少想确保粘贴起作用)。

@Directive({
  selector: '[someDate]'
})
export class SomeDateDirective{
  constructor(private el: ElementRef, private control : NgControl) {

  }

  @HostListener('input',['$event']) onEvent($event){
    $event.preventDefault();
    let data = $event.clipboardData.getData('text');
    setTimeout(() => {
      this.control.control.setValue(data.toUpperCase());
    }, 3000);
  }
}

input 改为 paste,以仅捕获onpaste事件。由于在使用 preventDefault()后会暂时消失,所以这可能有点奇怪。

这里有一个 Plunker: http://plnkr.co/edit/hsisILvtKErBBOXECt8t?p=preview


哇!这正是我需要的。虽然还没有实现,但肯定会起作用的。非常感谢 plunk。 - VSO
2
@VSO 很高兴我能帮到你。 - silentsod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接