AngularJS:$ viewContentLoaded在部分视图出现之前触发

Flo*_*ian 25 jquery dom ready angularjs angular-ui-router

对于局部视图,我想做一些我通常会做的JavaScript事情$(document).ready(function() {...}),例如将venet侦听器绑定到元素.我知道这对AngularJS和加载到"根"视图中的部分视图不起作用.

因此,我向监听$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 
});

[...]
Run Code Online (Sandbox Code Playgroud)

我想我做错了,因为如果这是一个常见的错误,必须在stackoverflow上发布更多帖子.

当我使用ui-routerui-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');
    }])

 [...]
Run Code Online (Sandbox Code Playgroud)

任何帮助表示赞赏.谢谢和亲切的问候

更新1:我将错误删除到以下用例:loginView.html如下所示:

<div id="loginContainer" style="width: 300px">
  <form id="loginForm" ng-submit="login(credentials)" ng-if="session.token == undefined">

[...]
Run Code Online (Sandbox Code Playgroud)

一旦我ng-if从div标签中删除它,它就会按预期工作.在呈现DOM之后触发事件,因此jQuery找到该元素.如果ng-if附加到div标签,则行为如首先描述的那样.

更新2:正如所承诺的,我添加了一个工作演示,显示添加ng-if指令时的不同行为.谁能指出我正确的方向?不要坚持使用登录表单,因为有更多的用例,我想根据某些表达式删除视图的某些部分,并在部分视图准备好后执行一些JavaScript操作.

你可以在这里找到工作演示:演示

T4d*_*deu 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);
    });
});
Run Code Online (Sandbox Code Playgroud)

修复了这里的演示:http://codepen.io/anon/pen/JoYPdv

但我强烈建议你使用指令做任何DOM操作,控制器不是为了那个.下面是一个如何执行此操作的示例: AngularJS中的简易dom操作 - 单击按钮,然后将焦点设置为输入元素

  • 这种方法的问题在于ui-router $ viewContentLoaded为每个视图触发.如果您在单个页面中有大量视图,则代码将多次执行.有没有办法让它在所有视图加载后只执行一次? (7认同)