Директива Angular не собирает служебные данные

Моя служба NavData

angular.module('navData', []).
    factory('NavData', function() {
        var navData = {};
        navData.depth = 0;
        navData.category_id = "";
        navData.category_name = "";
        navData.subcategory_id = "";
        navData.subcategory_name = "";
        return navData;
    });

получает значения от ui-router на некоторых страницах:

  var category = { 
    name: 'category',
    parent: site,
    url: '/categories/:category_id',
    onEnter: function(NavData, $stateParams){
      NavData.depth = 1;
      NavData.category_id = $stateParams.category_id;
      console.log(NavData);         
    },
    views: {
      'navigation': {
      templateUrl: 'partials/category-menu.html'
      },
      'content': {
      templateUrl: 'partials/category-images.html'
      }
    }
  };

Директива, появляющаяся на всех страницах, должна отслеживать изменения в службе и отражать их в настраиваемой функции хлебных крошек:

  .directive('breadcrumb', ['NavData', function(NavData){
    return {
      templateUrl: 'partials/breadcrumb.html',
      link: function(scope, elm, attrs, ctrl){
        scope.depth            = NavData.depth;
        scope.category_id      = NavData.category_id;
        scope.category_name    = NavData.category_name;
        scope.subcategory_name = NavData.subcategory_name;

        var doStuff = function(navdata){
          console.log("watching depth: " + navdata.depth);
          console.log("watching cat_id: "+ navdata.category_id);
        };
        scope.$watch(NavData.depth, doStuff(NavData), true);
        scope.$watch(NavData.category_id, doStuff(NavData), true);
      }

    };
  }])

Однако, похоже, что scope. $ Watch не работает. Это мой журнал:

watching depth: 0 directives.js:28
watching cat_id:  directives.js:29
watching depth: 0 directives.js:28
watching cat_id:  directives.js:29
Object {depth: 1, category_id: "1", category_name: "", subcategory_id: "", subcategory_name: ""} app.js:25

Что я делаю неправильно?


comment
Вы пробовали $ смотреть scope.deth, а не factory?   -  person Thomas Pons    schedule 22.09.2013
comment
Я просто пробовал, но без разницы. (Не то, чтобы я ожидал этого: почему?)   -  person arden    schedule 22.09.2013
comment
будет хорошо, если у вас есть скрипач или Plunker   -  person Maxim Shoustin    schedule 22.09.2013
comment
Вы имеете в виду, что это работает на скрипачей?   -  person arden    schedule 22.09.2013


Ответы (2)


Ваша первая ошибка находится в scope.$watch() 1-м аргументе: это либо выражение (строка), вычисленное в данном scope, либо функция, возвращающая значение; значение сохраняется, и функция запускается в каждом цикле дайджеста; если новое значение отличается, запускается слушатель (2-й аргумент).

Итак, первое исправление:

scope.$watch(function() {
    return NavData.depth,
}, .../*other arguments, see below*/);

Второй аргумент тоже неверен! Ожидается, что это будет функция, вы предоставляете возвращаемое значение функции (которое, кстати, не определено для doStuff). Эта функция 2-го аргумента получает новое значение (возвращаемое 1-м аргументом выше), старое значение и область видимости. В вашем случае вас не волнует новое / старое значение. Итак, полное решение должно быть:

scope.$watch(function() { // decide the watched value
    return NavData.depth,
}, function() { // what to do when the value changes
    // do stuff and reference NavData normally
});
person Nikos Paraskevopoulos    schedule 22.09.2013
comment
Благодарность! по какой-то причине я не знал, что вы можете передать функцию в качестве 1-го аргумента - person neaumusic; 03.08.2014
comment
Я установил свою собственную директиву таким образом, но наблюдатель вызывается только один раз? scope.$watch ()-> return myFactory.aVariable, ()-> console.log myFactory.aVariable - person kittyminky; 09.04.2015

Предполагая, что NavData изменяется только ui-router onEnter обратными вызовами, вы могли бы пропустить весь NavData объект и $watch реализацию.

Просто транслируйте событие при каждом onEnter обратном вызове:

onEnter: function($rootScope, $stateParams){
   $rootScope.$broadcast("NavDataChanged", {
       depth: 1,
       category_id: $stateParams.category_id
       /* (any other former NavData properties) */
   });
}

И ваша директива будет выглядеть так:

.directive('breadcrumb', [function(){
    return {
      templateUrl: 'partials/breadcrumb.html',
      link: function(scope, elm, attrs, ctrl){
        scope.$on("NavDataChanged", function(event, navData) {
            scope.depth = navData.depth;
            scope.category_id = navData.category_id;
            // any other former NavData properties and doStuff code
        });
      }
    };
  }])

Упрощенная версия здесь.

person Konstantinos Provatas    schedule 31.10.2013