user36322 user36322 - 7 months ago 14
Javascript Question

Angular controller function doesn't seem to work consistently when called inside directive

In my HTML I have something like this

<div class="form-group small-spacer" ng-repeat="bar in ctrl.foo.bars track by $index">
//irrelevant stuff deleted
<div class="col-md-1 col-xs-3">
<btn class="btn btn-block" double-click="ctrl.removeBar($index)" double-click-class="btn-warning btn-danger">X</btn>
</div>
</div>


I have a simple directive whose purpose is to just make sure the user clicks twice before doing anything rash.

function doubleClick($document) {
return {
restrict: 'A',
scope: {
doubleClick: '&'
},
link: function($scope, elem, attr) {
var classes = attr.doubleClickClass.split(' ');
var warningClass = classes[0], dangerClass = classes[1];

//used to ensure user clicks twice
var bIsTargeted = false;

//add the inital warning class
elem.addClass(warningClass);

var checkClick = function(event){
if(!elem[0].contains(event.target)){
if (bIsTargeted){
elem.removeClass(dangerClass);
elem.addClass(warningClass);
}
bIsTargeted = false;
}else{
if (bIsTargeted){
$scope.doubleClick();
}else{
elem.removeClass(warningClass);
elem.addClass(dangerClass);
}

bIsTargeted = !bIsTargeted;
}
}

$document.on('click', checkClick);

$scope.$on('$destroy', function() {
console.log('DESTROY!');
$document.off('click', checkClick);
});
}
};
}


In my ctrl.removeBar function:

this.removeBar = function(index){
console.log('deleted' + index)
vm.foo.bars.splice(index, 1);
console.log(vm.foo.bars);
}


When I click the double-click btn twice, the "deleted" log from ctrl.removeBar shows up, and the second log confirms that the bar object is spliced from the bars array. However, the DOM doesn't update most of the time and when it does, about a quarter of the time, it updates 5 seconds later. In the cases it doesn't update, it seems like the scope isn't destroyed either because there is no "DESTROYED" log from $scope.on('$destroy'). I tried adding an ng-click to the button like so:

<btn class="btn btn-block" ng-click="ctrl.removeBar($index)" double-click="ctrl.removeBar($index)" double-click-class="btn-warning btn-danger">X</btn>


In this case, the DOM is modified immediately 100% of the time and likewise for the "DESTROYED" log. This leads me to think I must have messed something up when calling the function from the directive. Any ideas what I did wrong?

Answer

Your click handler needs to do $scope.$apply() after it makes changes to the AngularJS model so that the framework knows to update the DOM.

For more moreinformation, see AngularJS $rootScope API Reference -- $apply.