在AngularJS完成渲染HTML之后运行jQuery代码
在控制器中,我使用$ http或$ resource服务获取一些JSON数据。 然后我把这个数据写在$ scope中,AngularJS更新页面的HTML结构。 我的问题是,我需要知道是什么新的大小(宽度和高度)的列表(我的意思是,HTML DOM元素)充满Angular ng-repeat
指令。 因此,我必须在Angular完成更新DOM结构之后运行JavaScript代码。 什么是正确的方法来做到这一点? 我在过去的四个小时里search了互联网,但是我找不到解决我的问题的方法。
这是我如何接收JSON数据:
var tradesInfo = TradesInfo.get({}, function(data){ console.log(data); $scope.source.profile = data.profile; $scope.trades = $scope.source.profile.trades; $scope.activetrade = $scope.trades[0]; $scope.ready = true; init(); //I need to call this function after update is complete });
这是init()
函数中发生的事情:
function init(){ alert($('#wrapper').width()); alert($('#wrapper').height()); }
我知道这个问题一定有一些容易解决的问题,但我现在不能find它。 提前致谢。
其实在这种情况下,angular度的方式不是简单的方法,但唯一正确的方法:)
你必须写一个指令,并附加到你想知道的高度的元素。 从控制器中,您可以播放一个事件,该命令会捕获事件,并且您可以执行DOM操作。 从来没有在控制器。
var tradesInfo = TradesInfo.get({}, function(data){ console.log(data); $scope.source.profile = data.profile; ... $scope.$broadcast('dataloaded'); }); directive('heightStuff', ['$timeout', function ($timeout) { return { link: function ($scope, element, attrs) { $scope.$on('dataloaded', function () { $timeout(function () { // You might need this timeout to be sure its run after DOM render. element.width() element.height() }, 0, false); }) } }; }]);
Olivér的答案是好的,但有一个问题:如果您忘记广播事件,您的JavaScript将不会运行,而您的数据可能已经改变。 另一个解决scheme是观察范围的变化,例如:
var tradesInfo = TradesInfo.get({}, function(data) { console.log(data); $scope.profile = data.profile; // ... }); directive('heightStuff', ['$timeout', function($timeout) { return { scope: { myData: '=' }, link: function($scope, element, attrs) { $scope.$watch('myData', function() { $timeout(function() { // You might need this timeout to be sure its run after DOM render. element.width() element.height() }, 0, false); }) } }; } ]);
<div height-stuff my-data="profile"></div>
这样, 每次数据更改时都会调用javascript函数,而不需要任何自定义事件。
另一个使用JQuery的build议。 必须通过在指令中生成的网格来完成此工作。 我想滚动到网格中的特定行。 使用$ emit从指令向父控制器广播:
在控制器中:
['$timeout',function($timeout){ ... $scope.$on('dataloaded', function () { $timeout(function () { // You might need this timeout to be sure its run after DOM render. $scope.scrollToPosition(); }, 0, false); }); $scope.scrollToPosition = function () { var rowpos = $('#row_' + $scope.selectedActionID, "#runGrid").position(); var tablepost = $('table', "#runGrid").position(); $('#runGrid').scrollTop(rowpos.top - tablepost.top); }
在指令中
.directive('runGrid',['$timeout', function ($timeout) { // This directive generates the grip of data return { restrict: 'E', //DOM Element scope: { //define isolated scope list: '=', //use the parent object selected: "=" }, templateUrl: '/CampaignFlow/StaticContent/Runs/run.grid.0.0.0.0.htm', //HTML template URL controller: ['$scope', function ($scope) { //the directive private controller, whith its private scope //$scope.statusList = [{ data_1: 11, data_2: 12 }, { data_1: 21, data_2: 22 }, { data_1: 31, data_2: 32 }]; //Controller contains sort functionallity $scope.sort = { column: null, direction: 1 } $scope.column = null; $scope.direction = "asc"; $scope.sortColumn = function (id) { if(id!=$scope.column) { $scope.column = id; $scope.direction = "asc"; } else { $scope.column = null; } } $scope.toggleDir = function () { $scope.direction = ($scope.direction == "asc") ? "desc" : "asc"; } $scope.$emit('dataloaded'); }] }; }])
这是网格指令html模板的一个片段:
<div style="overflow-y:auto;height: 200px;" id="runGrid"> <table class="table table-striped" style="table-layout:fixed"> <tbody> <tr ng-repeat="status in list" id="row_{{status.action_id}}" ng-class="(status.action_id==selected)?'selected':''"> <td>
列表和选定的参数是从使用该指令的html注入的
<run-grid list="list" selected="selectedActionID"></run-grid>
我想补充一个答案,因为前面的答案认为,在完成ngRepeat之后需要运行的代码是一个angular码,在这种情况下,所有的答案都给出了一个很好而简单的解决scheme,以及万一重要的消化生命周期阶段,你可以看看Ben Nadel的博客,除了使用$ parse而不是$ eval。
但是根据我的经验,正如OP所说,通常在最终编译的DOM上运行一些jQuery插件或方法,在这种情况下,我发现最简单的解决scheme是使用setTimeout
创build指令,因为setTimeout
函数获取推到浏览器队列的末尾,一切都完成后,它始终是正确的,通常是ng-repeat
,它是父母postLinkingfunction后继续
angular.module('myApp', []) .directive('pluginNameOrWhatever', function() { return function(scope, element, attrs) { setTimeout(function doWork(){ //jquery code and plugins }, 0); }; });
谁想知道为什么不使用$超时,它会导致另一个摘要循环是完全不必要的。
编辑:
Thanx到drzaus链接如何使用$超时没有导致摘要http://www.codelord.net/2015/10/14/angular-nitpicking-differences-between-timeout-and-settimeout/