Angular JS viewContentLoaded загрузка дважды при начальной загрузке главной страницы

Я заметил, что при загрузке моей начальной страницы мой viewContentLoaded запускается дважды, почему?

app.run(function 
    ($rootScope,$log) {
      'use strict';
      $rootScope.$state = $state;
      $log.warn("gets here");

      $rootScope.$on('$viewContentLoaded',function(){
        $log.warn("gets here2");
      });
    });

Выход на загрузку страницы

"gets here" 
"gets here2" 
"gets here2"

И моя маршрутизация следующим образом

$urlRouterProvider.when('', '/');

  // For any unmatched url, send to 404
  $urlRouterProvider.otherwise('/404');

  $stateProvider
    .state('home', {
      url: '/',
      templateUrl: 'views/search.html',
      controller: 'SearchCtrl'
    })

Мой индекс .html

  <div id="canvas">
    <ng-include src="'views/partials/header.html'"></ng-include>
    <!-- container -->
    <div ui-view ></div>
    <!-- /container -->
    <ng-include src="'views/partials/footer.html'"></ng-include>
  </div>

Ответ 1

Это просто спецификация реализации директивы uiView. Он запускает событие $viewContentLoaded во время фазы инициализации (ссылки). На этом этапе пока неизвестно, но событие все еще запущено.

И после того, как событие будет запущено снова, как только служба $state действительно разрешит ваше домашнее состояние, перейдет в него, загрузит шаблоны и т.д.

Итак, чтобы подвести итог, это происходит не из-за плохой конфигурации, а из-за того, что ваши шаблоны загружаются дважды. Это просто, как работает uiView.

Вы даже можете проверить это, полностью комментируя свои определения состояний и большую часть вашего содержимого index.html(за исключением ui-view). $viewContentLoaded все равно будет запущен один раз.

Исходные коды:

Объявление директивы uiView:

{
    restrict: 'ECA',
    terminal: true,
    priority: 400,
    transclude: 'element',
    compile: function (tElement, tAttrs, $transclude) {
      return function (scope, $element, attrs) {
        ...
        updateView(true);
        ...
      }
    }
 }

и updateView.

    function updateView(firstTime) {
      ...
      currentScope.$emit('$viewContentLoaded');
      currentScope.$eval(onloadExp);
    }

Для получения дополнительной информации см. полный исходный код GitHub - viewDirective.js

Ответ 2

Почему он получает вызов дважды?

Я уверен, что ваша страница serach.html снова содержит ui-view, которая вызывает попытку загрузить представление и в конце $emiting событие $viewContentLoaded. Просто так много числа ui-view, отображаемых на html, что, несомненно, будет $emit событием $viewContentLoaded.


Как вы хотите, чтобы ваше событие получало вызов только один раз, вы должны поместить событие в $stateChangeSuccess, который будет гарантировать, что он будет запущен только один раз после того, как все ui-представления будут загружены через состояние.

код

$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){ 
   ///...code here 
});

Ответ 3

Это может произойти, когда SearchCtrl будет вызываться дважды.

например.

$stateProvider
    .state('home', {
      url: '/',
      templateUrl: 'views/search.html',
      controller: 'SearchCtrl'
    })

и index.html

<body ng-controller="SearchCtrl">
    <div id="canvas">
    <ng-include src="'views/partials/header.html'"></ng-include>
    <!-- container -->
    <div ui-view ></div>
    <!-- /container -->
    <ng-include src="'views/partials/footer.html'"></ng-include>
  </div>
</body>