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':
I select '8300 Fauntleroy Way Southwest, Seattle, WA, United States':
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
If we use two way binding syntax for ngModel the value will be updated. So the default (ngModelChange) function will update the value of ngModel property. i.e., user.Name . And the second (ngModelChange) will be triggered printing the user name value in the console.
The ngModel directive is a directive that is used to bind the values of the HTML controls (input, select, and textarea) or any custom form controls, and stores the required user value in a variable and we can use that variable whenever we require that value. It also is used during form validations.
ngModel is responsible for: Binding the view into the model, which other directives such as input , textarea or select require.
This directive is used by itself or as part of a larger form. Use the ngModel selector to activate it. It accepts a domain model as an optional Input . If you have a one-way binding to ngModel with [] syntax, changing the domain model's value in the component class sets the value in the view.
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>
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With