2016-11-04 154 views
3

我正在使用指令在AngularJS 1.5中创建组件库。因此,我的指示需要隔离范围。AngularJS指令不更新回调范围

我的一些指令有回调,所以你可以传入一个函数来被指令调用。但是,当该指令调用该回调函数时,似乎并没有像我期望的那样完全更新$ scope属性的更改。

这里是一个Plunker,显示此行为: http://embed.plnkr.co/Rg15FHtHgCDExxOYNwNa/

下面是代码的样子:

<script> 
    var app = angular.module('myApp', []); 
    app.controller('Controller', ['$scope',function($scope) { 
     // initialize the value to something obvious 
     $scope.clickersValue = "BEFORE"; 

     // when this call back is called we would expect the value to be updated by updated by the directive 
     $scope.clickersCallback = function() { 
     //$scope.$apply(); // $apply is not allowed here 
     $scope.clickersValueRightAfterCall = $scope.clickersValue; 
     console.log("clickersCallback: scope.clickersValue", $scope.clickersValue); 
    }; 
    } 
]); 

app.directive('clicker', [function() { 
    return { 
    restrict: 'EA', 
    template: '<div ng-click="clicked()">click me!</div>', 
    controller: ['$scope', function($scope) { 
     $scope.clicked = function() { 
     console.log("you clicked me."); 
     $scope.newValue = 'VALID'; 
     $scope.myUpdate(); 
     } 
    }], 
    scope: { 
     "newValue": "=", 
     "myUpdate": "&" 
    } 
    }; 
}]); 
</script> 

所以当clickersCallback被调用的clickersValue属性仍然有旧值。我曾尝试使用$ scope。$ apply,但当然当另一个更新发生时它是不允许的。我也尝试使用controller_bind,但得到了同样的效果。

回答

2

将代码包装在clickersCallback函数中的$timeout函数中。

$timeout(function() { 
    $scope.clickersValueRightAfterCall = $scope.clickersValue; 
    console.log("clickersCallback: scope.clickersValue", $scope.clickersValue); 
}); 

Updated plunker

的$超时不会产生类似“$消化正在进行中”错误,因为$超时告诉角度,目前的周期后,有一个超时等待,这样就保证了那么digest循环之间不会有任何冲突,因此$ timeout的输出将在新的$ digest循环上执行。 source

编辑1:由于OP低于所述,该指令的用户不应该写在他的回调函数的任何“特殊”的代码。

为了实现这种行为,我将$ timeout从de控制器更改为指令。

控制器回调函数(没有改变):

$scope.clickersCallback = function() { 
    $scope.clickersValueRightAfterCall = $scope.clickersValue; 
    console.log("clickersCallback: scope.clickersValue", $scope.clickersValue); 
}; 

指令码(注入$超时的指令):

$scope.clicked = function() { 
    console.log("you clicked me."); 
    $scope.newValue = 'VALID'; 
    $timeout(function() { 
     $scope.myUpdate(); 
    }); 
} 

Updated plunker

+1

Gabriel,感谢您的创意。但是,这要求指令的用户在他们的代码中做一些特殊的事情。我真的正在寻找一种方式,指令用户可以像使用ng-click一样使用表达式。但是,我仍然赞成你的建议。 – Toddsden

+1

也许你可以在'$ timeout'中的'$ scope.myUpdate();'调用中包含指令。那是你要的吗? [plunker](https://embed.plnkr.co/4ZuiTsDL3KGUX9ZN1NH2/) –

+1

是的!那正是我想要的!我在你的建议后尝试过,但我肯定在代码中弄错了。你可以发布这个答案,以便我可以标记它的答案?不能够感谢你,这太棒了。 – Toddsden