AngularJS:AngularJS渲染模板后如何运行其他代码?

gor*_*ash 178 javascript jquery dom angularjs

我在DOM中有一个Angular模板.当我的控制器从服务获取新数据时,它会更新$ scope中的模型,然后重新呈现模板.到目前为止都很好.

问题是我需要在模板重新渲染之后做一些额外的工作并且在DOM中(在这种情况下是一个jQuery插件).

似乎应该有一个事件要听,比如AfterRender,但我找不到任何这样的东西.也许一个指令是一种可行的方式,但它似乎也太早了.

这是一个概述我的问题的jsFiddle:Fiddle-AngularIssue

==更新==

根据有用的评论,我相应地切换到一个指令来处理DOM操作,并在指令中实现了一个模型$ watch.但是,我仍然有同样的基础问题; $ watch事件内部的代码在模板编译并插入DOM之前触发,因此,jquery插件总是在评估一个空表.

有趣的是,如果我删除异步调用,整个过程就可以了,所以这是朝着正确方向迈出的一步.

这是我更新的小提琴反映这些变化:http://jsfiddle.net/uNREn/12/

dan*_*jar 63

首先,混淆渲染的正确位置是指令.我的建议是用像这样的指令来包装DOM操纵jQuery插件.

我有同样的问题,想出了这个片段.它使用$watch$evalAsync确保您的代码在ng-repeat已经解析的指令和已{{ value }}渲染的模板之后运行.

app.directive('name', function() {
    return {
        link: function($scope, element, attrs) {
            // Trigger when number of children changes,
            // including by directives like ng-repeat
            var watch = $scope.$watch(function() {
                return element.children().length;
            }, function() {
                // Wait for templates to render
                $scope.$evalAsync(function() {
                    // Finally, directives are evaluated
                    // and templates are renderer here
                    var children = element.children();
                    console.log(children);
                });
            });
        },
    };
});
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助你防止一些斗争.


dip*_*old 39

这篇文章很旧,但我将你的代码更改为:

scope.$watch("assignments", function (value) {//I change here
  var val = value || null;            
  if (val)
    element.dataTable({"bDestroy": true});
  });
}
Run Code Online (Sandbox Code Playgroud)

jsfiddle.

我希望它对你有所帮助

  • 这已被弃用了吗?当我尝试这个时,它实际上只是在*渲染DOM之前调用*.它是依赖于影子dom还是什么? (8认同)

Mar*_*cok 35

按照Misko的建议,如果你想要异步操作,那么代替$ timeout()(这不起作用)

$timeout(function () { $scope.assignmentsLoaded(data); }, 1000);
Run Code Online (Sandbox Code Playgroud)

使用$ evalAsync()(它确实有效)

$scope.$evalAsync(function() { $scope.assignmentsLoaded(data); } );
Run Code Online (Sandbox Code Playgroud)

小提琴.我还添加了一个"删除数据行"链接,它将修改$ scope.assignments,模拟对数据/模型的更改 - 以显示更改数据的工作原理.

" 概念概述"页面的" 运行时"部分说明,当您需要在当前堆栈帧之外但在浏览器呈现之前发生某些事情时,应使用evalAsync.(在这里猜测......"当前堆栈帧"可能包括Angular DOM更新.)如果您需要在浏览器呈现后发生某些事情,请使用$ timeout.

但是,正如您已经发现的那样,我认为这里不需要异步操作.

  • `$ scope.$ evalAsync($ scope.assignmentsLoaded(data));`对IMO没有任何意义.`$ evalAsync()`的参数应该是一个函数.在您的示例中,您在注册函数以便稍后执行时调用该函数. (4认同)

fuz*_*on9 26

我发现最简单(便宜又开朗)的解决方案就是在渲染的最后一个元素的末尾添加一个带有ng-show ="someFunctionThatAlwaysReturnsZeroOrNothing()"的空跨度.检查是否应显示span元素时,将运行此函数.执行此函数中的任何其他代码.

我意识到这不是最优雅的做事方式,但是,它对我有用......

我有一个类似的情况,虽然稍微颠倒了我需要在动画开始时删除加载指示器,在移动设备上角度初始化比要显示的动画要快得多,并且使用ng-cloak是不够的,因为加载指示器是在显示任何实际数据之前删除.在这种情况下,我只是将我的返回0函数添加到第一个渲染元素,并在该函数中翻转隐藏加载指示符的var.(当然我在此功能触发的加载指示器中添加了一个ng-hide.

  • 这肯定是一个黑客,但它正是我需要的.强制我的代码在渲染后完全运行(或非常接近完全).在一个理想的世界里,我不会这样做,但我们在这里...... (3认同)

Mis*_*ery 7

我想你正在寻找$ evalAsync http://docs.angularjs.org/api/ng.$ro​​otScope.Scope#$evalAsync

  • 感谢您的评论。也许我对 Angular 太陌生,但我没有看到如何将它应用到我的代码中。有什么例子可以指给我看吗? (2认同)