Подтвердить что ты не робот

AngularJS: $viewContentLoaded, выпущенный до частичного просмотра

Для частичного представления я хочу сделать некоторые материалы JavaScript, которые я обычно делал бы с $(document).ready(function() {...}), например. свяжите венец-слушателей с элементами. Я знаю, что это не работает для 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: Я удалил ошибку до следующей версии usecase: loginView.html выглядит следующим образом:

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

[...]

Как только я удаляю ng-if из тега div, он работает так, как ожидалось. Событие запускается после рендеринга DOM, поэтому jQuery находит элемент. Если ng-if прикреплен к тегу div, поведение будет описано вначале.

ОБНОВЛЕНИЕ 2: Как и было обещано, я добавил рабочую демонстрацию, в которой показано различное поведение при добавлении директивы ng-if. Может ли кто-нибудь указать мне правильное направление? Не придерживайтесь формы входа в систему как таковой, так как есть много других вариантов использования, когда я хочу удалить определенные части представления на основе некоторого выражения и сделать некоторые файлы JavaScript после частичного просмотра.

Здесь вы можете найти рабочую демонстрацию: Демо

4b9b3361

Ответ 1

Это связано с циклом digest angular, это о том, как angular работает под капотом, привязыванием данных и т.д. Есть большие учебники, объясняющие это.

Чтобы решить вашу проблему, используйте $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, контроллер не для этого. Вот пример того, как это сделать: Простое манипулирование домом в AngularJS - нажмите кнопку, затем установите фокус на элемент ввода

Ответ 2

Я решил эту проблему с помощью директив. Добавьте один директиву в свой элемент (например, <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:)

Ответ 3

Это ответ Аиду немного позже, но может помочь кому-то другому. Я настраиваю службу, которую позже я смогу позвонить с контроллера или директивы.

'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();
        }

    };
});