2015-12-31 168 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