AngularJS,绑定switch-case的范围?

And*_*eas 8 angularjs

为了掌握AngularJS,我决定使用其中一个示例,具体来说,只需在Todo示例中添加一个"完整"屏幕,当用户输入5个todos时,它使用一个switch-case切换到另一个div .代码可以在http://jsfiddle.net/FWCHU/1/获得,如果有任何用途的话.

但是,似乎每个switch-case都有自己的范围($ scope.todoText不可用),但是在这种情况下可以使用addTodo()中的"this"来访问它.到目前为止一切都那么好,但是我想要在switch-case之外访问todoText(在switch-case里面),我该怎么做呢?我是否可以将switch-case范围绑定到模型,是否可以通过其他方式访问,还是应该以其他方式解决?

PS.我不是要找到上面代码的任何解决方案,我很确定我知道如何在不使用switch-case的情况下解决它,我想了解范围在这种情况下如何工作!

Glo*_*opy 8

马克有一些很棒的建议!确保您还查看了AngularJS Batarang Chrome扩展程序,以查看各种范围及其值(以及其他内容).请注意,它似乎不适用于jsFiddle.

我不确定如何直接访问内部作用域,但这是通过绑定到对象而不是基元来访问外部作用域中的相同文本的一种方法.

1)todoText在控制器中声明为对象而不是基元:

$scope.todoText = {text: ''};
Run Code Online (Sandbox Code Playgroud)

2)绑定todoText.text而不仅仅是todoText:

<form ng-submit="addTodo()">
    <input type="text" ng-model="todoText.text" size="30" placeholder="add new todo here">
    <input class="btn-primary" type="submit" value="add">
</form>
Run Code Online (Sandbox Code Playgroud)

3)修改要使用的现有功能todoText.text:

$scope.addTodo = function() {
    $scope.todos.push({text:$scope.todoText.text, done:false, width: Math.floor(Math.random() * 100) + 50});
    $scope.todoText.text = '';
};
Run Code Online (Sandbox Code Playgroud)

看一下这个小提琴并注意当你输入内容时文本框下面显示的文本是访问todoText.text外部范围.

如果您更改代码以使用基元(如此小提琴),则父作用域todoText不会反映您对文本框所做的任何更改.这可能更多地与JavaScript如何复制引用值有关(请参阅此文章以获取更多信息),而不是AngularJS特定的事情.

  • 我没有看过AngularJS代码,但我假设在创建新范围时,值会被复制到子范围.使用原语,您将获得值本身的副本,而使用对象,它会复制指向同一对象的引用的值.基元是不可变的,因此如果基本范围中的基元发生变化,则会创建一个未与父基元值相关联的新值.对于对象,父范围和子范围中的引用都是相同的,因此对属性的任何更改都是可见的.这个小提琴显示了我想要解释的内容:http://jsfiddle.net/uQzyh/ (2认同)

Mar*_*cok 5

Update2: 现在我对AngularJS有了更多了解,这里有一个更好的答案.

说我想在s​​witch-case之外访问todoText(在switch-case里面),我该怎么做呢?

父作用域无法访问子作用域.(根据Angular开发人员的说法,这种限制的一个原因是为了更容易对范围进行内存管理.)(好吧,你可以使用$$ childHead和$$ childTail来访问子范围,但你不应该!)

我是否可以将switch-case范围绑定到模型,是否可以通过其他方式访问,还是应该以其他方式解决?

从子范围访问父模型有三种常用方法:

  1. 执行@Gloopy建议:在父作用域中创建一个对象,然后在子作用域中引用该对象的属性.
  2. 在子作用域中使用$ parent来访问父作用域及其属性,甚至是原始属性.
  3. 在父作用域上调用方法

要转换你的小提琴使用$ parent:

<input type="text" ng-model="$parent.todoText" ...

$scope.addTodo = function() {
   $scope.todos.push({text: $scope.todoText, ...
   $scope.todoText = '';
Run Code Online (Sandbox Code Playgroud)

正如我在Gloopy的回答中提到的那样,ng-repeat和ng-switch都将新的子范围原型继承自父范围.ng-repeat还将循环变量/项复制到新的子范围(以及@Gloopy描述的原语与对象的细微差别).ng-switch不会从父作用域复制任何内容.

要查看内部/子范围的外观,请在ng-switch-when之后添加以下内容:

<a ng-click="showScope($event)">show scope</a>
Run Code Online (Sandbox Code Playgroud)

并将其添加到您的控制器:

$scope.showScope = function(e) {
    console.log(angular.element(e.srcElement).scope());
}
Run Code Online (Sandbox Code Playgroud)

Update1 :(为了清晰起见,删除了添加到错误建议中的[删除])

对于这种情况,AngularJS正在创建额外的内部作用域(隐式),而你真的不需要/需要另一个控制器,我喜欢Gloopy的解决方案.一项服务(我最初在下面提出的建议)[这样做的错误方法] 可能在这里有点过分.我也喜欢Gloopy的解决方案不需要在控制器方法中使用'this'.

原始答案 :(删除了错误的建议,为了清晰起见,添加了[])

要查看创建范围的位置(如果您还没有尝试过,那么它很方便):

.ng-scope { margin: 4px; border: 1px dashed red }
Run Code Online (Sandbox Code Playgroud)

要在switch-case之外访问todoText(因此在其范围之外),你实际上是在询问控制器间通信,因为涉及多个范围.您有几个选择,但服务可能是最好的.将数据(需要共享)存储在服务中,并将该服务注入需要访问数据的每个控制器.

对于您的具体示例,我认为您需要将控制器附加到每个交换机案例并将服务注入其中,以访问共享数据.

另请参见AngularJS:如何在控制器之间传递变量?.

其他选择:

在内部作用域中使用$ scope.$ parent是[一种方法来执行此操作 - 请参阅上面的Update2] 不推荐,因为控制器将对数据的呈现方式做出假设.

建议不要使用$ rootScope,除非是简单的一次性应用程序.共享数据可能会开始具有自己的生命,并且$ rootScope不是发生这种情况的地方.服务更易于重用,添加行为等.

使用$ scope.$ emit是另一种选择,但它似乎很乱并且有点奇怪:发出事件来共享数据(而不是触发行为).

[在父范围内使用对象可能是最好的 - 请参阅@ Gloopy的答案.]