Angularjs Angular JS指令是否有渲染后回调?
我刚刚收到指令,要拉入一个模板以附加到其元素,如下所示:Angularjs Angular JS指令是否有渲染后回调?,angularjs,Angularjs,我刚刚收到指令,要拉入一个模板以附加到其元素,如下所示: # CoffeeScript .directive 'dashboardTable', -> controller: lineItemIndexCtrl templateUrl: "<%= asset_path('angular/templates/line_items/dashboard_rows.html') %>" (scope, element, attrs) -> element.pa
# CoffeeScript
.directive 'dashboardTable', ->
controller: lineItemIndexCtrl
templateUrl: "<%= asset_path('angular/templates/line_items/dashboard_rows.html') %>"
(scope, element, attrs) ->
element.parent('table#line_items').dataTable()
console.log 'Just to make sure this is run'
# HTML
<table id="line_items">
<tbody dashboard-table>
</tbody>
</table>
#咖啡脚本
.指令“dashboardTable”,->
控制器:lineItemIndexCtrl
模板URL:“
(范围、元素、属性)->
element.parent('table#line_items')。dataTable()
console.log“只是为了确保它已运行”
#HTML
我还使用了一个名为DataTables的jQuery插件。它的一般用法如下:$('table#some_id').dataTable()。您可以将JSON数据传递到dataTable()调用中以提供表数据,或者您可以在页面上已经有数据,它将完成其余的工作。。我正在做后一个,在HTML页面上已经有了行
但问题是,我必须在DOM就绪后调用表#line_项上的dataTable()。上面我的指令在将模板附加到指令的元素之前调用dataTable()方法。有没有一种方法可以在追加后调用函数
谢谢你的帮助
安迪回答后更新1:
我想确保link方法只有在所有内容都在页面上之后才会被调用,所以我修改了指令进行了一个小测试:
# CoffeeScript
#angular.module(...)
.directive 'dashboardTable', ->
{
link: (scope,element,attrs) ->
console.log 'Just to make sure this gets run'
element.find('#sayboo').html('boo')
controller: lineItemIndexCtrl
template: "<div id='sayboo'></div>"
}
#咖啡脚本
#角模(…)
.指令“dashboardTable”,->
{
链接:(范围、元素、属性)->
console.log“只是为了确保它运行”
元素.find('#sayboo').html('boo'))
控制器:lineItemIndexCtrl
模板:“”
}
而且我确实在div#sayboo中看到了“boo”
然后我尝试调用jquerydatatable
.directive 'dashboardTable', ->
{
link: (scope,element,attrs) ->
console.log 'Just to make sure this gets run'
element.parent('table').dataTable() # NEW LINE
controller: lineItemIndexCtrl
templateUrl: "<%= asset_path('angular/templates/line_items/dashboard_rows.html') %>"
}
指令“dashboardTable”,->
{
链接:(范围、元素、属性)->
console.log“只是为了确保它运行”
element.parent('table').dataTable()#新行
控制器:lineItemIndexCtrl
模板URL:“
}
那里运气不好
然后我尝试添加一个超时:
.directive 'dashboardTable', ($timeout) ->
{
link: (scope,element,attrs) ->
console.log 'Just to make sure this gets run'
$timeout -> # NEW LINE
element.parent('table').dataTable()
,5000
controller: lineItemIndexCtrl
templateUrl: "<%= asset_path('angular/templates/line_items/dashboard_rows.html') %>"
}
指令“dashboardTable”($timeout)->
{
链接:(范围、元素、属性)->
console.log“只是为了确保它运行”
$timeout->#新行
element.parent('table').dataTable()
,5000
控制器:lineItemIndexCtrl
模板URL:“
}
这就行了。所以我想知道非计时器版本的代码出了什么问题 您可以使用“link”函数,也称为postLink,它在放入模板后运行
app.directive('myDirective', function() {
return {
link: function(scope, elm, attrs) { /*I run after template is put in */ },
template: '<b>Hello</b>'
}
});
app.directive('myDirective',function(){
返回{
link:function(scope、elm、attrs){/*我在模板放入*/}后运行,
模板:“你好”
}
});
如果你打算制定指令,请仔细阅读这篇文章,这是一个很大的帮助:我也有同样的问题,我相信答案确实是否定的。请看,还有一些 Angular可以跟踪它为操作DOM而进行的所有函数调用是否都已完成,但由于这些函数可能触发异步逻辑,而这些逻辑在返回后仍在更新DOM,因此Angular不可能知道这一点。任何回调有时都可能起作用,但依靠它是不安全的 我们用setTimeout试探性地解决了这个问题,正如您所做的那样
(请记住,并非所有人都同意我的观点-你应该阅读上面链接上的评论,看看你的想法。)我也有同样的问题,但使用Angular+DataTable和
fnDrawCallback
+$compiled嵌套指令。我在我的fnDrawCallback
函数中放置了$timeout来修复分页渲染
在示例之前,基于行\分组源:
var myDrawCallback = function myDrawCallbackFn(oSettings){
var nTrs = $('table#result>tbody>tr');
for(var i=0; i<nTrs.length; i++){
//1. group rows per row_grouping example
//2. $compile html templates to hook datatable into Angular lifecycle
}
}
var myDrawCallback=函数myDrawCallbackFn(oSettings){
var nTrs=$(“表#结果>正文>tr”);
对于(var i=0;i我使用以下指令得到了这个结果:
app.directive('datatableSetup', function () {
return { link: function (scope, elm, attrs) { elm.dataTable(); } }
});
app.directive('aDirective', function () {
return {
scope: {
input: '=',
control: '='
},
link: function (scope, element) {
function functionThatNeedsInput(){
//use scope.input here
}
if ( scope.input){ //We already have input
functionThatNeedsInput();
} else {
scope.control.init = functionThatNeedsInput;
}
}
};
})
$scope.control = {};
...
$scope.input = 'some data could be async';
if ( $scope.control.functionThatNeedsInput){
$scope.control.functionThatNeedsInput();
}
在HTML中:
<table class="table table-hover dataTable dataTable-columnfilter " datatable-setup="">
如果未提供第二个参数“delay”,则默认行为是在DOM完成渲染后执行函数。因此,使用$timeout代替setTimeout:
$timeout(function () {
//DOM has finished rendering
});
虽然我的答案与datatables无关,但它解决了DOM操作的问题,例如jQuery插件初始化用于以异步方式更新内容的元素的指令
不需要实现超时,只需添加一个可以监听内容更改(甚至额外的外部触发器)的手表即可
在我的例子中,当ng重复创建了我的内部DOM之后,我使用这个变通方法初始化了一个jQuery插件——在另一个例子中,我使用它只是在controller上更改scope属性之后操作DOM
HTML:
注意:在我的directive watch属性中,可以想象任何任意表达式,而不是将myContent变量强制转换为bool
注意:像上述示例中那样隔离作用域对于每个元素只能执行一次-尝试在同一元素上使用多个指令执行此操作将导致$compile:multidir错误-请参阅:没有一个适合我的解决方案接受使用超时。这是因为我使用的模板是动态调用的在postLink期间正在创建y
但是,请注意,当超时将调用的函数添加到浏览器队列时,可能会出现“0”的超时,这将在角度渲染引擎之后发生,因为该函数已经在队列中
指的是:
这是一个指令,它指示在浅渲染之后编程的动作。浅层的意思是,它将在元素渲染之后进行评估,这将与它的内容呈现时无关。因此,如果你需要一些子元素做一个后渲染动作,你应该考虑使用它:
define(['angular'], function (angular) {
'use strict';
return angular.module('app.common.after-render', [])
.directive('afterRender', [ '$timeout', function($timeout) {
var def = {
restrict : 'A',
terminal : true,
transclude : false,
link : function(scope, element, attrs) {
if (attrs) { scope.$eval(attrs.afterRender) }
scope.$emit('onAfterRender')
}
};
return def;
}]);
});
然后你可以做:
或使用任何有用的表达式,如:
我回答这个问题可能会迟到。但还是有人会从我的回答中受益
我有类似的问题,在我的情况下,我不能改变指令,因为它是
app.directive('myDirective', [ function(){
return {
restrict : 'A',
scope : {
myDirectiveWatch : '='
},
compile : function(){
return {
post : function(scope, element, attributes){
scope.$watch('myDirectiveWatch', function(newVal, oldVal){
if (newVal !== oldVal) {
// Do stuff ...
}
});
}
}
}
}
}]);
define(['angular'], function (angular) {
'use strict';
return angular.module('app.common.after-render', [])
.directive('afterRender', [ '$timeout', function($timeout) {
var def = {
restrict : 'A',
terminal : true,
transclude : false,
link : function(scope, element, attrs) {
if (attrs) { scope.$eval(attrs.afterRender) }
scope.$emit('onAfterRender')
}
};
return def;
}]);
});
$scope.render=false;
//this will fire after load the the page
angular.element(document).ready(function() {
$scope.render=true;
});
<canvas ng-if="render"> </canvas>
app.directive('aDirective', function () {
return {
scope: {
input: '=',
control: '='
},
link: function (scope, element) {
function functionThatNeedsInput(){
//use scope.input here
}
if ( scope.input){ //We already have input
functionThatNeedsInput();
} else {
scope.control.init = functionThatNeedsInput;
}
}
};
})
<a-directive control="control" input="input"></a-directive>
$scope.control = {};
...
$scope.input = 'some data could be async';
if ( $scope.control.functionThatNeedsInput){
$scope.control.functionThatNeedsInput();
}