Search code examples
angularjsangularjs-directive2-way-object-databinding

angular directive (2-way-data-binding) - parent is not updated via ng-click


I have a nested directive with an isolated scope. An Array of objects is bound to it via 2 way data binding.

.directive('mapMarkerInput',['mapmarkerService', '$filter', '$timeout',function(mapMarkerService, $filter, $timeout) {
    return {
        restrict: 'EA',
        templateUrl:'templates/mapmarkerInputView.html',
        replace: true,
        scope: {
            mapmarkers: '='
        },
        link: function($scope, element, attrs) {

            //some other code

            $scope.addMapmarker = function($event) {
                var mapmarker = {};
                var offsetLeft = $($event.currentTarget).offset().left,
                    offsetTop = $($event.currentTarget).offset().top;

                mapmarker.y_coord = $event.pageY - offsetTop;
                mapmarker.x_coord = $event.pageX - offsetLeft;
                mapmarker.map = $scope.currentMap;
                $scope.mapmarkers = $scope.mapmarkers.concat(mapmarker);
            };

            $scope.deleteMapmarker = function(mapmarker) {
                var index = $scope.mapmarkers.indexOf(mapmarker);
                if(index !== -1) {
                    $scope.mapmarkers.splice(index,1);
                }
            };

            //some other code
       )
}]);

These 2 functions are triggered via ng-click:

<img ng-if="currentMap" ng-click="addMapmarker($event)" ng-src="/xenobladex/attachment/{{currentMap.attachment.id}}" />
<div class="mapmarker-wrapper" ng-repeat="mapmarker in shownMapmarkers" ng-click="setZIndex($event)" style="position: absolute; top: {{mapmarker.y_coord}}px; left: {{mapmarker.x_coord}}px;">
     <!-- some other code -->
     <div class="form-group">
          <label>Name:</label>
          <input ng-model="mapmarker.name" value="mapmarker.name" class="form-control" type="text">
     </div>
     <div class="form-group">
          <label>Description:</label>
          <input ng-model="mapmarker.description" value="mapmarker.description" class="form-control" type="text">
     </div>
     <button class="btn btn-danger" ng-click="deleteMapmarker(mapmarker)">Delete</button>
</div>

As you can see I am binding the name and description directly via ng-model and that works just fine. The properties are also available in the parent scope, but neither the delete nor the add works (its changed within the directives scope, but not the parent scope).

As far as I understand these changes should be applied, because I'm calling these functions via ng-click and I have other examples where this works. The only difference is, that I am binding to an array of objects and not a single object / property.

I tried using $timer and updateParent() ($scope.$apply() does not work -> throws an exception that the function is already within the digest cycle) but with no success, so it looks like these changes are not watched at all.

The directive code looks like this:

<map-marker-input ng-if="$parent.formFieldBind" mapmarkers="$parent.formFieldBind"></map-marker-input>

It is nested within a custom form field directive which gets the correct form field template dynamically and has therefore template: '<div ng-include="getTemplate()"></div>' as template, which creates a new child scope - that's why the $parent is needed here.

The binding definitely works in one way, the expected data is available within the directive and if I'm logging the data after changing it via delete or add, it's also correct, but only from the inside of the directive.

Because ng-model works I guess there might be a simple solution to the problem.

UPDATE

I created a plunkr with a simplified version: http://plnkr.co/85oNM3ECFgCzyrSPahIr

Just click anywhere inside the blue area and new points are added from within the mapmarker directive. Right now I dont really prevent adding points if you delete or edit these - so you'll end up with a lot of points fast ;-)

There is a button to show the data from the parent scope and from the child scope.

If you edit the name or description of the one existing point that will also be changed in the parent scope (bound via ng-model). But all new points or deletions are ignored (bound within the functions called via ng-click).


Solution

  • If you want to update the parent scope, you need to access it via $parent once more, i change

    mapmarkers="$parent.formFieldBind"
    

    to :

    mapmarkers="$parent.$parent.formFieldBind"
    

    ng-include create one more scope, so you need to access the parent once more.

    http://plnkr.co/edit/27qF6ABUxIum8A3Hrvmt?p=preview