2016-11-04 197 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