简体   繁体   中英

AngularJS directive scope not updating

Background

I have created a directive to keep track of selection on my table. The directive works with ng-repeat and adds a click event to every element created by the ng-repeat, when a user clicks on an element the directive updates the records selection atribute and sets the item as the selection on the controller scope for later use.

Problem

The parent scope (CampaignDetailCtrl) is not getting updated by my directive click event, the selection attribute is never changing an is always null. I understand that using the scope: false causes the directive to use the parent scope but doesn't seem to work as planned.

Question

How do I set the value of $scope.selection on my CampaignDetailCtrl from the directive?

Controller

app.controller('CampaignDetailCtrl', ['$scope', 'CampaignService', '$stateParams', '$modal', function ($scope, CampaignService, $stateParams, $modal) {
$scope.selection = null;

//...

}])

Directive

app.directive('selection', function () {
var directive = {
    restrict: 'A',
    scope: false,
    link: function (scope, element, attrs) {
        var selected_class = 'selected';

        var repeat_line = attrs.ngRepeat;

        if (!repeat_line) {
            throw 'selection must be used along side ngRepeat';
        }

        var repeat_parts = repeat_line.split(' in ');
        var selected_item = scope.$eval(repeat_parts[0]);

        scope.$watch(scope.selection, function(newVal, oldVal) {

        });

        /**
         * Item click handler
         */
        var handleClick = function (event) {
            selected_item.selected = !selected_item.selected;
            scope.selection = selected_item;

            if(selected_item.selected) {
                element.addClass(selected_class);
            } else {
                element.removeClass(selected_class);
            }
        };

        element.on('click', handleClick);
    }
};

return directive;

});

HTML

<div ng-controller="CampaignDetailCtrl">
...

<table>
    <thead>
    <tr>
        <th>...</th>
    </tr>
    </thead>
    <tbody>
    <tr selection ng-repeat="channel in record.channels" ng-dblclick="edit(channel)">
        <td>{{...}}</td>
    </tr>

    </tbody>
</table>
...

Example

See simple jsBin example: http://jsbin.com/xoxez/3/

You have a shadowing issue. You can read more about it at different places, but remember ng-repeat creates a new child scope for each item.

To avoid scope shadowing, use a . in your ngModel:

$scope.selection = {
    noShadow: null
};

// later: $scope.selection.noShadow

Working example here: http://jsbin.com/teyofukerilo/1/

While this will just work fine, it would be better to have isolated scopes on your selection and wrap them into a selected directive. The selected directive would then be 'required' by the others and communication between them would be managed by the controller defined on the selected directive. You can read more about 'communicating' directives here: http://www.thinkster.io/angularjs/sMgLuIxf02/angularjs-directive-to-directive-communication https://docs.angularjs.org/guide/directive (see require attribute)

Let me know if you need help implementing it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM