ng-init + ng-controller:控制器范围内的奇怪行为

tet*_*chy 12 angularjs-scope

我是Angular的新手但很享受它的方法.我有一个HTML文件,我ng-init在一个<div>元素中初始化一个变量,我也在声明一个带有该ng-controller指令的控制器:

<div ng-controller="myCtrl" ng-init='foo="bar"'>
Run Code Online (Sandbox Code Playgroud)

如果我console.log是$scope控制器脚本中的对象,我可以看到其他foo属性列出的属性,但是当我尝试从同一个脚本访问它时,它给了我undefined.我也在使用Batarang,它向我展示了<div>-scope 的模型,其中还包括该foo属性.

我从第二个答案中知道将变量传递给AngularJS控制器,最佳实践?我可以通过将我的ng-init指令移到外部来解决问题<div>,但我想知道幕后真正发生的事情.任何帮助非常感谢,提前感谢.

编辑

div元素中指令的顺序无关紧要.即使ng-init之前已指定,问题仍然存在ng-controller

tet*_*chy 18

好吧,我想我弄明白了

ng-init由于Angular执行其编译阶段的方式,外部/内部els 的不同行为出现了.编译包括不同的步骤.在这种情况下最相关的是:

  1. 控制器实例化
  2. 预链接
  3. 链接
  4. postlinking

在每个DOM节点的基础上按此顺序发生(即对于每个节点,控制器代码,如果存在,则在任何预链接,链接或后链接f之前执行)

ng-initpre在指定的节点上注册一个-link f,这$eval是指令的内容(在我的例子中,f为fooprop 指定一个值).因此,当执行同一节点的控制器代码时,支柱尚不存在,这符合@ Aron的答案

在编译阶段,Angular在深度优先的基础上从根向下遍历DOM,这意味着父元素在其子元素之前被编译.将ng-init指令放在外部el中允许子节点的控制器继承外部的作用域.这解释了'外部'黑客

hack @Aron指向在prop上注册一个观察者,这样,当prop $eval在预链接阶段最终被操作时,回调f可以找到它

我建议基于异步JS和Angular特性的其他两个可能的hacks(参见这个jsFiddle).一个涉及使用setTimeoutJS本机f,而另一个涉及更多'Angular'和度假$evalAsync

imho,Angular ng-init对声明的意图实施指令存在缺陷.我已经破解了Angular的代码来试验各种各样的实现.这并不困难(即使在删除ng-init指令本机代码之前添加了2行代码),并且在应用于上面的jsFiddle中的代码时也能正常工作,但我还没有在复杂的应用程序上测试它.对于那些感兴趣的人,这是我正在做的事情(参考文献v 1.2.0-rc2):

  • 在applyDirectivesToNodef块中,我声明了一个非初始化的nodeHasInitData局部变量
  • 在同一个f中,在为本地directiveNamevar分配directive.nameprop值后,我对"ngInit"静态字符串进行测试,静态字符串是Angular ng-init在节点上声明时指定给指令的规范化名称
  • 如果测试通过,我设置nodeHasInitData为true.如果测试失败则没有做任何事情( - > nodeHasInitData保留undefined在关闭中)
  • 在nodeLinkFnf块中,在if检查节点中是否存在控制器的块之前(上面列表中的步骤1),我正在添加一个值的测试nodeHasInitData(我可以这样做,因为nodeLinkFn在内部定义applyDirectivesToNode)
  • 如果测试通过,我调用scope.$eval(attrs.ngInit),这是本机ng-init指令的prelink f .这两个scope和attrs是原生PARAMS nodeLinkFn,所以他们都可用.如果测试失败,什么都不做
  • 这样,我已经将步骤2中的初始化1移动到新的步骤0,在执行相应的控制器代码之前将其提供给内部el范围.

实际上,我已经复制了它,因为ng-init指令定义的预链接f 仍然存在.但是,这并不是很重要,我认为通过更改/删除指令对象可以轻松避免这种情况

编辑

为了避免复制,出于上述hack的说明性目的,将ngInitDirectiveAngular var 的赋值代码替换为安全的是安全的.var ngInitDirective = valueFn({});