2014-11-23 46 views
24

我有一个应用程序,我正在建设角度,我有大约8-10视图建立。 所有的视图都有一个共同的页脚,基于视图和我需要有条件地显示/隐藏页脚上的一些内容的一组业务规则。AngularJS:ng-include和ng-controller

所以。 我有控制器为每个视图,然后一个脚注。 我使用ng-include包含了常见的页脚布局,其中我包括的html引用了ng控制器中的页脚控制器。

的Index.html

<body ng-controller="MainCtrl as vm"> 
    <p>Message from Main Controller '{{vm.mainMessage}}'</p> 
    <div ng-include="'commonFooter.html'"></div> 
</body> 

commonFooter.html

<div ng-controller="FooterCtrl as vm"> 
    <p>Message from Footer Controller '{{vm.message}}'</p> 
    <p ng-show="vm.showSomthing">Conditional footer Content</p> 
</div> 

我希望每个视图控制器来确定页脚的状态和具体内容是否被隐藏。 (以下shouldDisplaySomthingInFooter)

app.controller('MainCtrl', function($scope) { 
    var vm = this; 
    vm.mainMessage= 'HEELO'; 
    vm.shouldDisplaySomthingInFooter = true; 
    window.console.log('Main scope id: ' + $scope.$id); 
}); 

然后我本来打算,在FooterController将达到回父控制器和拔出具体设置以使/基于业务规则禁止的内容。

app.controller('FooterCtrl', function($scope) { 
    var vm = this; 
    vm.message = 'vm footer'; 

    window.console.log('Footer scope id: ' + $scope.$id); 
    window.console.log('Footer parent scope id: ' + $scope.$parent.$id); 
    window.console.log('Footer grandparent scope id: ' + $scope.$parent.$parent.$id); 
    window.console.log('Footer grandparent scope name: ' + $scope.$parent.$parent.mainMessage); 
    window.console.log('Footer grandparent scope condition: ' + $scope.$parent.$parent.shouldDisplaySomthingInFooter); 

    vm.showSomthing = false; //how to pull from parent scope to bind the ng-show to a value set in the parent from within a ng-include? 
}); 

我这里有这个例子: http://plnkr.co/edit/ucI5Cu4jjPgZNUitY2w0?p=preview

什么我发现是我,当我到达到父范围,拉出它是回来为未定义的内容,我不知道为什么。

我可以看到范围通过检查scopeid嵌套到祖父级别,我相信这是因为ng-include在视图范围下面添加了一个额外的范围层。 outout from console in attached example

加分:如果我不能使用$ scope对象,并且可以坚持使用var vm = this;这样做的方式,那将是更可取的。但乞丐不能选择器:)

app.controller('MainCtrl', function($scope) { 
    var vm = this; 

非常感谢您提前。

回答

28

如果范围的外控制器vm和您的内部控制器foo,然后你可以很容易将它们分开,并提及vm withi在内部控制器。

Demo

HTML

<body ng-controller="MainCtrl as vm"> 
    <p>Message from Main Controller '{{vm.mainMessage}}'</p> 
    <div ng-include="'commonFooter.html'"></div> 
</body> 

CommonFooter.html

<div ng-controller="FooterCtrl as footer"> 
    <p>Message from Footer Controller '{{footer.message}}'</p> 
    <p ng-show="vm.shouldDisplaySomethingInFooter">Conditional footer Content</p> 
</div> 

app.js

var app = angular.module('plunker', []); 

app.controller('MainCtrl', function() { 
    var self = this; 
    self.mainMessage = 'Hello world'; 
    self.shouldDisplaySomethingInFooter = true; 
}); 

app.controller('FooterCtrl', function() { 
    var self = this; 
    self.message = 'vm footer'; 
}); 

注意:为了清楚起见,我将您的var vm = this更名为var self = this,以减少视图与控制器之间的混淆。

预期输出:

output showing the conditionally hidden\shown items

3

您误解了控制器为语法(see documentation)的用途。这只是在本地范围内公开特定控制器的一种方式,以便您可以从模板访问其属性。当您在父级和页脚模板中使用someController as vm时,您不会在控制器之间创建连接或类似的任何连接。您只需在页脚范围内设置vm属性,因此,当您在页脚模板中使用它时,您正在访问页脚的控制器(并阻止了到父控制器的路径)。

对于你想要做的事情,你基本上不需要控制器作为语法。只需将您的数据正确地放在$scope上,并让范围层次结构为您完成剩下的工作。

在你父控制器:

$scope.features.rock = true; 
$scope.features.roll = false; 

在您的页脚模板

<p ng-show="features.rock">...</p> 
<p ng-show="features.roll">...</p> 

现在,您还可以查看和更改从其他控制器features(作为其范围是父控制器的范围后裔)。

2

我与你plunker拨弄左右,但也改变var vm = this;$scope,所以我在加分未能:-)

我会强烈建议不要的$scope.$parent使用准确的告诉你的原因。各种指令如ng-includeng-show等都生成自己的作用域。

如果有人在将来改变你的html并且有意或无意地增加了范围,你无法控制。

我建议使用驻留在您的MainCtrl上的函数并通过继承范围访问它们。

Plunker

$scope.getShouldShow = function() { 
    return $scope.shouldDisplaySomthingInFooter; 
    }; 
    $scope.setShouldShow = function(val) { 
    $scope.shouldDisplaySomthingInFooter = val; 
    }; 

    $scope.getMainMessage = function() { 
    return $scope.mainMessage; 
    } 

而且美其名曰:

<p ng-show="getShouldShow();">Conditional footer Content</p> 

和:

window.console.log('Footer grandparent scope name: ' + $scope.getMainMessage()); 
    window.console.log('Footer grandparent scope condition: ' + $scope.getShouldShow());