我有一个简单的表单,其输入字段与指令相关联:
<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函数的值是字段的旧值,而不是您选择的自动完成值。
答案 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
希望这会对你有帮助......