10

I'm stuck on how to access and change an inputs ngModel value using a directive. The outcome of the issue is that the model's address value doesn't update when I select the desired address...it's just set to what I actually typed into the input, rather than final value of the input.

I type '830':

enter image description here

I select '8300 Fauntleroy Way Southwest, Seattle, WA, United States':

enter image description here

Resulting value:

{ address: '830' } 

Desired value:

{ address: '8300 Fauntleroy Way Southwest, Seattle, WA, United States' } 

In AngularJS I could do this:

(function() { 'use strict'; angular .module('casemanagerApp') .directive('googleplace', googleplace); function googleplace() { var directive = { require: 'ngModel', link: link }; return directive; function link(scope, element, attrs, model) { var options = { types: [], componentRestrictions: {} }; scope.gPlace = new google.maps.places.Autocomplete(element[0], options); // jshint ignore:line google.maps.event.addListener(scope.gPlace, 'place_changed', function() { // jshint ignore:line scope.$apply(function() { model.$setViewValue(element.val()); }); }); } } })(); 

But now that I'm trying to convert it Angular 2, I'm a little stuck. Here's what I have so far on the conversion:

/// <reference path="../../../../typings/browser/ambient/googlemaps/index.d.ts"/> import { Directive, ElementRef, OnInit } from '@angular/core'; @Directive({ selector: '[google-places]' }) export class GooglePlaces implements OnInit { constructor(private _el: ElementRef) { } ngOnInit() { let gPlace = new google.maps.places.Autocomplete(this._el.nativeElement); google.maps.event.addListener(gPlace, 'place_changed', () => console.log(this._el.nativeElement)); } } 

Usage:

<input type="text" ngControl="address" placeholder="Enter a location" [(ngModel)]="subject.address" #address="ngForm" google-places required> 

The heart of the issue is I don't understand how to do the equivalent of model.$setViewValue(element.val()); in Angular 2.

Any assistance would be greatly appreciated.

Plunker

4
  • This looks related stackoverflow.com/questions/36106350/… maybe you can get some ideas. Commented Jun 2, 2016 at 18:00
  • Hi @GünterZöchbauer. Unfortunately those solutions didn't work for me. I've created a Plunker though to better illustrate the issue. plnkr.co/edit/1xMjzo Commented Jun 2, 2016 at 19:22
  • What about Thierrys approach? Commented Jun 2, 2016 at 19:25
  • @GünterZöchbauer Yeah that doesn't work either. They just both change the value of the input without updating the value of the model. Commented Jun 2, 2016 at 19:25

3 Answers 3

7

I ended up getting this to work, although I don't understand why it works because I'm not binding ngModelChange to the element...but it works.

Directive:

/// <reference path="../../../../typings/browser/ambient/googlemaps/index.d.ts"/> import { Directive, ElementRef, Output, EventEmitter, OnInit, NgZone } from '@angular/core'; @Directive({ selector: '[google-places]' }) export class GooglePlaces implements OnInit { @Output() ngModelChange: EventEmitter<any> = new EventEmitter(false); options = { types: ['address'], componentRestrictions: { country: "us" } }; constructor( private _el: ElementRef, private _ngZone: NgZone) { } ngOnInit() { let gPlace = new google.maps.places.Autocomplete(this._el.nativeElement, this.options); google.maps.event.addListener(gPlace, 'place_changed', () => { this._ngZone.run(() => this.ngModelChange.emit(this._el.nativeElement.value)); }); } } 

Component Template:

<input type="text" class="form-control" ngControl="address" id="subjectAddress" placeholder="Enter a location" [(ngModel)]="subject.address" #address="ngForm" google-places required> 
Sign up to request clarification or add additional context in comments.

2 Comments

This does not work for me. I'm assuming it probably worked for 2.0.0-rc.1 (what was avail on June 2), but probably broken in 3 different ways since then.
"I don't understand why it works because I'm not binding ngModelChange to the element" - you actually do, whe you use [(ngModel)]="subject.address" it is translated to [ngModel]="subject.address" and (ngModelChange)="subject.address = $event"
1

I would inject the ControlValueAccessor associated with your input. Here is a sample:

@Directive({ selector: '[test]' }) export class TestDirective { constructor(@Inject(NG_VALUE_ACCESSOR) private valueAccessor:ControlValueAccessor) { setTimeout(() => { this.valueAccessor[0].writeValue('test'); }, 1000); } } 

See this plunkr for example: https://plnkr.co/edit/owhBHdBncAxlzwJ8xkfq?p=preview.

1 Comment

Thanks. However this updates the value of the input but not the value of the model. I've created a plunker to further explain the issue: plnkr.co/edit/1xMjzo
0

This is what i did with my datepicker , Might help.

//Create a method in your component to change the model dateChanged(date) { this.hero.bday = date; } public ngOnInit() { //CREATE A REFERERENCE TO YOUR COMPONENT var component:CreateEventComponent = this; $("#bday").datepicker({ dateFormat: "dd-mm-yy", altFormat: "dd-mm-yy", onSelect: function (dateText, datePicker) { //UPDATE YOUR MODEL FORM JQUERY CODE. component.dateChanged(dateText); } }); } 

1 Comment

is ngOnInit in a separate directive? How is the directive getting access to the component?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.