Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 doesn't update input value modified by third-party libraries

Tags:

I have a simple form with its input field associated to a directive:

<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>

The directive changes the input field through the use of a third party library. In my particular case, this is an autocomplete/typeahead Jquery plugin. This plugin provides options to the user and after selecting an option, it changes the value of the input field.

However, Angular doesn't update its property query.value and therefore, passes the old value to the onPost method.

The directive looks something like this:

@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(); 
     }

}

I was suggested to use UpdateValue, but I can't see how to use it inside a directive. That led me to look at @ViewChild, but it doesn't seem to work in directives, although I could be mistaken.

I also tried to force an update by injecting ChangeDetectorRef, but I didn't see any difference. This is what I did:

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 is triggered when the user selects an option from the autocomplete plugin. For the plugin, it looks a bit different because it binds to some event, but I think this illustrates the idea.

I would appreciate any suggestions.

UPDATE:

This is a plnkr to show the main issue using the typeahead.js library. If you write a letter in the input field, it will show you some options. Select one of them and the value of the input field will change accordingly. However, when you submit the form (clicking on the input field or pressing enter), an alert will show that the value that was passed to the onPost function was the old value of the field and not the autocompleted value you selected.

like image 659
Robert Smith Avatar asked Jul 10 '16 06:07

Robert Smith


1 Answers

Provisional solution: Demo. Passing the form to the custom directive and using updateValue to manually change the value:

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);
      });

This works, but let me know if there is a standard approach to solve this kind of issue.

like image 145
Robert Smith Avatar answered Oct 04 '22 09:10

Robert Smith