2015-12-31 166 views
1

如果我有兩個不同的指令與孤立範圍,並且他們共享一個控制器,他們不應該共享控制器的$scope


實際上,我有以下情形:

  1. 我打電話到服務器並通過它的一些參數,讓我們稱之爲xy
  2. 的服務器或者返回一些數據,或者返回null表明該數據不可用。
  3. 如果返回數據,我需要顯示一個按鈕;如果用戶單擊該按鈕,它將在獨立的div中顯示數據。
  4. 如果數據回來,我不顯示的按鈕。

我一直在努力實現這個爲一組鏈接指令。我試圖這樣做,因爲這個「組件」將在應用程序中重複使用多次,並且我試圖在兩個指令中執行此操作,因爲我找不出任何其他方式來創建單個指令控制兩個不同的元素。

除了有很多,他們需要鏈接xy值。所以,如果我有特別的xy一個按鈕,然後點擊它只會切換使用相同xy值的顯示區域的知名度。有效地,給定視圖將具有不同的xy值。

無論如何,我有一個潛在的有效的解決方案,但我似乎有與共享的範圍問題。當我點擊按鈕時,我有記錄語句正確地表明我們觸發了「顯示」邏輯。但是div的ng-if中的日誌語句始終將相同的邏輯評估爲false,並且不會顯示。

我的解決辦法是在三個部分:

  • 一種用於按鈕
  • 一種用於「展示」
  • 控制器,該控制器由兩個

我共享指令指令有一個微不足道的工作示例,我將在下面分享。在這篇文章的末尾還有一個Plunkr網址。

下面是HTML。中間的<p>標籤僅用於說明兩個指令在物理上不相鄰。

<trigger x="apple" y="2" ></trigger> 
<p>Some unrelated dom content...</p> 
<display x="apple" y="2"></display> 

這是trigger指令,它是按鈕:

app.directive("trigger", function() { 
    return { 
    restrict: "E", 
    scope: { 
     x : "@", 
     y : "@" 
    }, 
    transclude: false, 
    template: "<button ng-if='hasCalculation(x,y)' ng-click='toggle()'>Trigger x={{x}} & y={{y}}</button>", 
    controller: 'testController', 
    link: function(scope) { 
     scope.doSomeWork(); 
    } 
    }; 
}); 

這是display指令,這是爲了顯示數據時由按鈕切換:

app.directive("display", function() { 
    return { 
    restrict: 'E', 
    scope: { 
     x : '@', 
     y : '@' 
    }, 
    require: '^trigger', 
    transclude: false, 
    controller: 'testController', 
    template: "<p ng-if='shouldShow(x,y)'>{{getCalculation(x,y)}}</p>" 
    }; 
}); 

這是共享控制器,testController

app.controller("testController", ["$scope", function($scope) { 
    $scope.shouldShow = [[]]; 
    $scope.calculatedWork = [[]]; 
    $scope.doSomeWork = function() { 
    var workResult = "We called the server and calculated something asynchonously for x=" + $scope.x + " and y=" + $scope.y; 
    if(!$scope.calculatedWork[$scope.x]) { 
     $scope.calculatedWork[$scope.x] = []; 
    } 
    $scope.calculatedWork[$scope.x][$scope.y] = workResult; 
    }; 

    $scope.hasCalculation = function(myX, myY) { 
    var xRes = $scope.calculatedWork[myX]; 
    if(!xRes) { 
     return false; 
    } 
    return $scope.calculatedWork[myX][myY] 
    } 

    $scope.toggle = function() { 
    if(!$scope.shouldShow[$scope.x]) { 
     $scope.shouldShow[$scope.x] = []; 
    } 
    $scope.shouldShow[$scope.x][$scope.y] = !$scope.shouldShow[$scope.x][$scope.y]; 
    console.debug("Showing? " + $scope.shouldShow[$scope.x][$scope.y]); 
    } 

    $scope.isVisible = function(myX, myY) { 
    console.debug("Checking if we should show for " + myX + " and " + myY); 

    var willShow; 
    if(!$scope.shouldShow[myX]) { 
     willShow = false; 
    } else { 
     willShow = $scope.shouldShow[myX][myY]; 
    } 
    console.debug("Will we show? " + willShow); 
    return willShow; 
    } 

    $scope.getCalculation = function(myX, myY) { 
    if(!$scope.calculatedWork[myX]) { 
     return null; 
    } 
    return $scope.calculatedWork[myX][myY]; 
    } 
}]); 

這裏是Plunkr

如果您轉到Plunkr,您會看到正確呈現的觸發按鈕。如果單擊該按鈕,您將看到toggle()方法正確地將shouldShow的值翻轉爲與之前相反的值(該方法中有一個控制檯調試語句顯示其結果)。您還將看到isVisible方法的重新評估,該方法確定顯示屏是否應顯示 - 此總是返回false。

我認爲這與我保存相對於$scope的數據和可見性狀態有關。我對此的理解是,每條指令都有自己的$scope,但由於它們共享一個控制器,不應該共享控制器的$scope

回答

0

隔離範圍原型繼承父範圍的屬性。

在AngularJS中,子範圍通常從其父範圍通常原型繼承。這條規則的一個例外是使用範圍的指令:{...} - 這會創建一個不會原型繼承的「隔離」範圍。(和帶有包含指令的指令)這個構造通常用於創建「可重用組件」指示。在指令中,父範圍默認直接使用,這意味着無論您在指令中更改來自父範圍的內容是否也會在父範圍內更改。如果將scope設置爲true(而不是範圍:{...}),那麼原型繼承將用於該指令。

來源:https://github.com/angular/angular.js/wiki/Understanding-Scopes

此外,控制器不是單是一類...所以兩個指令不能共享控制器。他們每個實例化控制器。

如果您希望兩個控制器共享相同的數據,請使用factory