AngularJS가 HTML 렌더링을 완료 한 후 jQuery 코드 실행
컨트롤러에서 $ http 또는 $ resource 서비스를 사용하여 JSON 데이터를 얻습니다. 그런 다음이 데이터를 $ scope에 쓰고 AngularJS가 페이지의 HTML 구조를 업데이트합니다. 내 문제는 Angular ng-repeat
지시문으로 채워진 목록 (즉, HTML DOM 요소)의 새로운 크기 (너비 및 높이)가 무엇인지 알아야한다는 것입니다 . 결과적으로 Angular가 DOM 구조 업데이트를 마친 직후에 자바 스크립트 코드를 실행해야합니다. 이를 수행하는 올바른 방법은 무엇입니까? 지난 4 시간 동안 인터넷을 검색했지만 내 문제에 대한 해결책을 찾지 못했습니다.
이것은 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());
}
이 문제를 쉽게 해결할 수있는 방법이 있다는 것을 알고 있지만 지금은 찾을 수 없습니다. 미리 감사드립니다.
실제로이 경우 각도 방법은 쉬운 방법이 아니라 유일한 올바른 방법입니다. :)
지시문을 작성하고 높이를 알고 싶은 요소에 연결해야합니다. 컨트롤러에서 이벤트를 브로드 캐스트하면 지시문이 이벤트를 잡아서 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의 대답은 좋지만 문제가 있습니다. 이벤트를 브로드 캐스트하는 것을 잊으면 자바 스크립트가 실행되지 않지만 데이터가 변경되었을 수 있습니다. 또 다른 해결책은 범위의 변경 사항을 관찰하는 것입니다. 예를 들면 다음과 같습니다.
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>
이렇게 하면 맞춤 이벤트 없이도 데이터가 변경 될 때마다 자바 스크립트 함수가 호출 됩니다 .
JQuery로 작업하기위한 또 다른 제안. 지시문에서 생성 된 그리드에 대해이 작업을 수행해야했습니다. 그리드의 특정 행으로 스크롤하고 싶었습니다. $ 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가 완료된 후 실행하는 데 필요한 코드가 각도 코드라는 것을 받아들이 기 때문에 다른 답변을 추가하고 싶습니다.이 경우 위의 모든 답변은 위의 모든 답변이 다른 것보다 더 일반적인 솔루션을 제공합니다. 다이제스트 수명주기 단계가 중요한 경우 Ben Nadel의 블로그에서 $ eval 대신 $ parse를 사용하는 것을 제외하고 살펴볼 수 있습니다.
But in my experience, as the OP states, it is usually running some jQuery plugins or methods on the finally compiled DOM, which in that case I found that the most simple solution is to create a directive with a setTimeout
, since the setTimeout
function gets pushed to the end of the queue of the browser, its always right after everything is done in angular, usually ng-repeat
which continues after it's parents postLinking function
angular.module('myApp', [])
.directive('pluginNameOrWhatever', function() {
return function(scope, element, attrs) {
setTimeout(function doWork(){
//jquery code and plugins
}, 0);
};
});
For whoever wondering why not to use $timeout, its that it causes another digest cycle that is completely unnecessary.
EDIT:
Thanx to drzaus for the link to how to use $timeout without causing digest http://www.codelord.net/2015/10/14/angular-nitpicking-differences-between-timeout-and-settimeout/
'IT Share you' 카테고리의 다른 글
Team Foundation Server와 함께 Mercurial을 실제로 사용하십니까? (0) | 2020.11.08 |
---|---|
자식 요소를 부모보다 높은 Z- 색인으로 만드는 방법은 무엇입니까? (0) | 2020.11.08 |
Windows 용 Haskell IDE? (0) | 2020.11.08 |
RESTful API에서 객체 계층을 어떻게 처리해야합니까? (0) | 2020.11.08 |
계층 적 데이터를 저장하는 데 가장 적합한 NoSQL 데이터베이스 유형은 무엇입니까? (0) | 2020.11.08 |