对于部分视图,我想做一些我通常会对$(document).ready(function() {...})
执行的JavaScript操作,例如将venet侦听器绑定到元素。我知道这对AngularJS不起作用,部分视图加载到" root"图。
因此,我向侦听器添加了一个侦听器,用于侦听$viewContentLoaded
事件。调用了侦听器的函数,因此事件被触发但在我看来好像是在呈现局部视图之前。当我在侦听器函数中设置断点并使用firebug调试它时,我也没有看到元素,函数中的jquery选择也找不到局部视图的元素。
这就是控制器的样子:
angular.module('docinvoiceClientAngularjsApp')
.controller('LoginController', function ($scope, $rootScope) {
$scope.$on('$viewContentLoaded', function(event) {
console.log("content loaded");
console.log($("#loginForm")); // breakpoint here
});
[...]
我想我做错了,因为如果这是一个常见的错误,必须在stackoverflow上发布更多帖子。
当我使用 ui-router 和 ui-view 时,我会给你一个路由文件的摘录:
angular
.module('docinvoiceClientAngularjsApp', [
'ui.router',
'ngAnimate',
'ngCookies',
'ngResource',
'ngMessages',
'ngRoute',
'ngSanitize',
'ngTouch'
])
.config(function ($routeProvider, $stateProvider) {
$stateProvider
.state('login', {
url: '/',
templateUrl: 'components/login/loginView.html',
controller: 'LoginController'
})
.run(['$state', function ($state) {
$state.transitionTo('login');
}])
[...]
感谢任何帮助。谢谢和亲切的问候
更新1:我将错误删除到以下用例:loginView.html如下所示:
<div id="loginContainer" style="width: 300px">
<form id="loginForm" ng-submit="login(credentials)" ng-if="session.token == undefined">
[...]
一旦我从div标签中删除ng-if
,它就会按预期工作。在呈现DOM之后触发事件,因此jQuery找到该元素。如果ng-if
附加到div标签,则行为与第一次描述的相同。
更新2:正如所承诺的,我添加了一个工作演示,显示添加ng-if
指令时的不同行为。谁能指出我正确的方向?不要坚持使用登录表单,因为有更多的用例,我想根据某些表达式删除视图的某些部分,并在部分视图准备好后执行一些JavaScript操作。
您可以在此处找到工作演示:Demo
答案 0 :(得分:44)
这与角度消化周期有关,它是关于角度如何在引擎盖下工作,数据绑定等。有很好的教程解释这个。
要解决您的问题,请使用$ timeout,它将使代码在下一个周期执行,因为ng-if已经被解析:
app.controller('LoginController', function ($scope, $timeout) {
$scope.$on('$viewContentLoaded', function(event) {
$timeout(function() {
$scope.formData.value = document.getElementById("loginForm").id;
},0);
});
});
此处修正了演示:http://codepen.io/anon/pen/JoYPdv
但我强烈建议你使用指令做任何DOM操作,控制器不是为了那个。 这是一个如何做到这一点的例子: Easy dom manipulation in AngularJS - click a button, then set focus to an input element
答案 1 :(得分:1)
我在指令的帮助下解决了这个问题。将一个direcitve添加到您的元素(如<div my-dir></div>
)并对相应指令中的元素进行操作,如下所示,
app.directive('myDir', function () {
return {
restrict: 'A',
link: function (scope, element) {
// Do manipulations here with the help of element parameter
}
};
});
我还尝试了状态提供程序事件,例如$stateChangeSuccess
,$viewContentLoaded
,但无法解决问题。因为在这些事件被解雇之后,它需要花时间在DOM上进行渲染。
因此,我们可以遵循这种方法,在Angular JS中实现完美的结果和正确的实现方式:)
答案 2 :(得分:0)
这是对哈迪斯的回答有点晚,但可能会帮助其他人。我设置了一个服务,我稍后可以从控制器或指令中调用它。
'use strict';
app.factory('viewContentLoaded', function($q, $rootScope, $timeout) {
var viewContentLoaded = $q.defer(),
foo = function() {
$timeout(function() {
viewContentLoaded.resolve();
// Get all entries
}, 100);//Timeout
},
checkViewContenLoadedListner = $rootScope.$on('$viewContentLoaded', foo);//Rootscope
return {
getLoaded: function() {
return viewContentLoaded.promise;
},
removeViewContenListner: function() {
//Remove event listern on $viewContentLoaded no $off so call it will unsubscribe it
//$rootScope.$off('$viewContentLoaded', foo);//Rootscope
//Don't forget to unsubscribe later
checkViewContenLoadedListner();
}
};
});
在控制器或指令中包含viewContentLoaded并使用promise调用get函数。不要忘记将应用程序更改为您的应用程序名称,并包含要加载的服务文件。
viewContentLoaded.getLoaded().then(function(){
//Remove Listner when done
viewContentLoaded.removeViewContenListner();
//Your code to run
}, function(reason) {
//$log.error(reason);
});