Cedric Bongaerts Cedric Bongaerts - 3 months ago 19
AngularJS Question

Adding ng-model to directive

I have the following directive to reverse geocode a lat & long into a place:

/* global app*/

app.directive('reverseGeocode', function () {
return {
restrict: 'A',
template: '<div ng-model="autoLocation"></div>',
link: function (scope, element, attrs) {
var geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(attrs.lat, attrs.lng);
geocoder.geocode({ 'latLng': latlng }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[1]) {
element.text(results[1].formatted_address);
} else {
element.text('Location not found');
}
} else {
element.text('');
}
});
},
require: "ngModel",
replace: true
}
});


But for some reason, it doesn't seem to retrieve the ng-model and display it:

<div class="form-group move-down" ng-class="{ 'has-error': place === null }">
<label for="place">Picture taken in:</label>
<input type="text" class="form-control" ng-if="!capture.geo" id="place" ng-model="place.formatted_address" ng-autocomplete options="options" required details="place" ng-click="checkPlace(place)"
uib-tooltip="Please pick the location where you captures your photo!"
tooltip-placement="top-right"
tooltip-trigger="mouseenter"
tooltip-enable="!details.formatted_address"
tooltip-class="tooltip">

// DIRECTIVE USED HERE
<reverse-geocode class="form-control" ng-if="capture.geo" lat="{{capture.latitude}}" lng="{{capture.longitude}}">
<div ng-show="place === null" class="noPlace">
<i class="glyphicon glyphicon-remove"></i> Please fill in a valid location!
</div>
</div>


What my goal is, is to display the location below using:

<div ng-if="capture.geo">Place: {{autoLocation}}</div>

Answer

First you need to drop restrict or at least use E (element) instead of A (attribute), since you are using the directive as element.

Second, you don't need to add or pass ng-model, which is a directive itself, to your directive. You can access the controller scope variable capture directly. If you prefer directive to have it's own, isolated scope, then you should two-way bind the controller variable to directive's scope using = (or @ if you prefer passing literal strings).

If I understood correctly, below is what you are after (simplified but functionality is there).

HTML

<body ng-controller="MyCtrl">
  lat <input type="number" ng-model="capture.lat">
  lng <input type="number" ng-model="capture.lng">
  <reverse-geocode capture="capture"></reverse-geocode>
</body>

JavaScript

angular.module('app', [])
.controller('MyCtrl', function($scope) {
  $scope.capture = {
    lat: 10.0,
    lng: 20.0
  };
})
.directive('reverseGeocode', function () {
  return {
    restrict: 'E',
    scope: {
      capture: '='
    },
    template: '<div ng-bind="autoLocation"></div>',
    link: function(scope) {
      scope.$watch('capture', function() {
        if (scope.capture.lat && scope.capture.lng) {
          scope.autoLocation = 'reverse geocode address for [' +
            scope.capture.lat + ' ' + scope.capture.lng + '] here';
        } else {
          scope.autoLocation = 'invalid coordinates';
        }
      }, true);
    },
  }; 
});

image

Comments