Angular 2不会更新第三方库修改的输入值

时间:2016-07-10 06:35:56

标签: javascript jquery angular

我有一个简单的表单,其输入字段与指令相关联:

<form id="scrollable-dropdown-menu">
  <input class="input-field" name="value" [someDirective] type="text"  [(ngModel)]="value" #query="ngModel" />
  <button (click)="onPost(query.value)" type="submit">Search</button>
</form>

该指令通过使用第三方库来更改输入字段。在我的特定情况下,这是一个autocomplete / typeahead Jquery插件。此插件为用户提供选项,选择选项后,它会更改输入字段的值。

但是,Angular不会更新其属性query.value,因此会将旧值传递给onPost方法。

该指令看起来像这样:

@Directive({
    selector: '[someDirective]',
})
export class MyDirective  {
     constructor(private elRef: ElementRef, private renderer: Renderer) {
         // this changes the value of the field if the user selects an option
         $('.input-field').plugin(); 
     }

}

我被建议使用UpdateValue,但我无法在指令中看到如何使用它。这导致我看看@ViewChild,但它似乎并没有在指令中工作,尽管我可能会弄错。

我还尝试通过注入ChangeDetectorRef来强制更新,但我没有看到任何差异。这就是我所做的:

my.directive.ts

import {ChangeDetectorRef} from '@angular/core';
@Directive({
    selector: '[someDirective]',
})
export class MyDirective  {
    constructor(private elRef: ElementRef, private renderer: Renderer, private detectorRef: ChangeDetectorRef) {
       $('.input-field').plugin(); 

       $('.input-field').my-plugin(':selected', ()=>{ 
          // do something... 
          this.detectorRef.detectChanges();
       })
    }



}

当用户从自动完成插件中选择一个选项时,会触发AfterSelection。对于插件,它看起来有点不同,因为它绑定到某个事件,但我认为这说明了这个想法。

我很感激任何建议。

更新

This是使用typeahead.js库显示主要问题的plnkr。如果您在输入字段中写了一个字母,它会显示一些选项。选择其中一个,输入字段的值将相应更改。但是,当您提交表单(单击输入字段或按Enter键)时,警报将显示传递给onPost函数的值是字段的旧值,而不是您选择的自动完成值。

5 个答案:

答案 0 :(得分:1)

临时解决方案:Demo。将表单传递给custom指令并使用updateValue手动更改值:

my.component.ts

<form *ngIf="active" #frm="ngForm">
    <input name="value" [myDirective]="frm" type="text" [(ngModel)]="value" #query="ngModel" />
    <button (click)="onPost(query.value)" type="submit">Search</button>
</form>

my.directive.ts

@Directive({
    selector: '[myDirective]',
})
export class MyDirective  {

    @Input('myDirectivev') query;
... 
$(this.elRef.nativeElement).my-plugin(':selected', (ev, suggestion) => {
        this.query.controls['value'].updateValue(suggestion);
      });

这有效,但请告诉我是否有解决此类问题的标准方法。

答案 1 :(得分:1)

我被告知有关Gitter的另一个解决方案。不幸的是,我不记得是谁告诉我这件事,而Gitter的搜索功能对我没有帮助。由于这个人没有发布他的解决方案,我将分享它,以造福可能感兴趣的人。

这个想法基本上是将整个字段作为参数传递给onPost(input)方法并访问输入字段value的{​​{1}}属性。

input.value

请注意输入字段中的@Component({ selector: 'my-app', template: ` <form id="scrollable-dropdown-menu" class="search-form"> <input name="value" class="form-control typeahead" typeahead type="text" data-provide="typeahead" [(ngModel)]="thing" #query /> <button (click)="onPost(query)" class="btn btn-default search-button" type="submit">Search</button> </form> `, directives: [TypeaheadDirective], providers: [] }) export class AppComponent { onPost(input) { alert(`Your current value is ${input.value}`); } } [(ngModel)]="thing"。我不完全确定为什么这会正确地更新其值并且本机尝试不会,但这比其他替代方案简单得多。 Here你可以找到一个演示。

答案 2 :(得分:1)

而不是

this.detectorRef.detectChanges();

使用

$('.input-field').trigger('input');
ControlValueAccessor使用的{p> ngModel侦听正常输入字段的input个事件。

答案 3 :(得分:1)

GünterZöchbauer是对的。您应该发送'input'事件来更新angular的模型。但JQuery触发器没有帮助。只有原生事件修复了这个

@Directive({
    selector: '[myDirective]',
})
export class MyDirective  {

...

  $(this.elRef.nativeElement).my-plugin(':selected', (ev, suggestion) => {
    const inputEvent: any = document.createEvent('CustomEvent');
    inputEvent.initEvent('input', true, true);
    el.dispatchEvent(inputEvent);
  });
}

答案 4 :(得分:0)

我认为Zone不知道第三方变量的变化,因此第三方变量没有反映在Angular中

您可以尝试将jQuery代码放在角度区域中,方法如下:

  • 导入区域:import {NgZone} from 'angular2/core'import {NgZone} from '@angular/core',具体取决于您使用的Angular 2版本;
  • zone: NgZone添加到MyDirective;
  • 的构造函数参数中
  • 将<{1}}替换为

    $('.input-field').plugin();

这是post about Change detection and Zone

希望这会对你有帮助......

相关问题