Angularjs — $ rootScope в функции директивной ссылки

Я задаю этот вопрос, потому что не совсем понимаю, как думать о rootscope как о зависимости, передаваемой директивам.

У меня есть директива, которая должна отображать некоторую информацию из $rootScope...

Я думал, что мне нужно передать $rootScope в директиву, но когда я пишу такую ​​директиву, кажется, что она работает.

.directive("myBar", function () {
 return {
    restrict: "E",
    transclude: true,
    replace: true,
    template:   '<div>' + 
                '<span ng-transclude></span>' + 
                '{{rsLabels.welcome}} {{rsUser.firstName}}!' + 
                '</div>'
}
})

Когда мне нужно это сделать?

.directive("myBar", function ($rootScope) {
 return {
    restrict: "E",
    transclude: true,
    replace: true,
    template:   '<div>' + 
                '<span ng-transclude></span>' + 
                '{{rsLabels.welcome}} {{rsUser.firstName}}!' + 
                '</div>'
}
})

Могу ли я и КАК мне использовать rootScope, если он мне нужен в функции ссылки директивы, или я должен делать это в контроллере директивы?

.directive("myBar", function ($rootScope) {
 return {
    restrict: "E",
    transclude: true,
    replace: true,
    link: function (scope, element, attrs, rootScope) {
        rootScope.rsUser = { firstName: 'Joe' };
        rootScope.rsUser = { welcome: 'Welcome' };
    },
    template:   '<div>' + 
                '<span ng-transclude></span>' + 
                '{{rsLabels.welcome}} {{rsUser.firstName}}!' + 
                '</div>'
}
})

Мои данные rootScope определены в функции запуска

 .run(function ($rootScope) {

  $rootScope.rsLabels = { 
      welcome: 'Welcome'
  };

  $rootScope.rsUser = { 
     firstName: 'Joe'
  };
});

Спасибо!


person GRowing    schedule 12.02.2014    source источник


Ответы (6)


Из моих экспериментов\опыта кажется, что, поскольку все $scopes в конечном итоге наследуются от $rootScope, вы сможете получить доступ к данным на нем, не запрашивая его как услугу, следуя стандартным правилам наследования прототипов javascript. Если бы вы установили для свойства scope в своей директиве значение false или {}, вы обнаружите, что больше не можете получить к нему доступ.

.directive("myBar", function($rootScope) {
    return {
        restrict: "E",
        scope: { /* Isolate scope, no $rootScope access anymore */ },
        transclude: true,
        replace: true,
        template: '<div>' + 
                  '<span ng-transclude></span>' + 
                  '{{rsLabels.welcome}} {{rsUser.firstName}}!' + 
                  '</div>'
    };
});

Пример: http://jsbin.com/bequy/1/edit.

person Mike Cheel    schedule 12.02.2014
comment
ах! Я понимаю. Как отметил Курт, это не лучший способ установить свойства приложения в angular, но мне нужно было понять rootScope, и это объясняет его лучше. Спасибо. Вы случайно не знаете, как получить доступ к области $root в функции ссылки директивы? - person GRowing; 13.02.2014
comment
Вы должны думать о $rootScope как о глобальном пространстве имен и не загромождать его. Вы можете внедрить его в свою директиву, но весь смысл директив в том, чтобы быть компонентом без слишком большого количества внешних зависимостей. Если вам нужно что-то из $rootScope, вы можете подумать о рефакторинге этого в службу. - person Mike Cheel; 13.02.2014
comment
Это имеет смысл. Я полагаю, что прибегал к использованию любых эквивалентов степеней свободы, эквивалентных глобальным, из-за необходимости сделать данные x доступными в любое время и не зная, как еще подойти к этому. Я использую localStorage для некоторых вещей, но теперь, глядя на cacheFactory и его расширенную версию, и на то, как они используют localstorage, я вижу свет. Спасибо! - person GRowing; 13.02.2014
comment
Установка области действия: true заставит это работать. Установив для него пустой хэш {} или false, вы изолируете область действия и разорвете цепочку наследования. (См. Объект определения директивы, область действия) code.angularjs.org /1.4.1/docs/api/ng/service/$compile (мой пример против 1.2.1, но он не изменился, насколько я могу судить). - person Mike Cheel; 29.06.2015

Вы можете сделать это следующим образом:

{{$root.rsLabels.welcome}}
person karaxuna    schedule 28.05.2014
comment
Спасибо, не так ли. Я использую link: function(scope, ...) { scope.$root } для доступа к $rootScope из директивы. - person ivkremer; 26.09.2014
comment
Да, я имею в виду, что искал в Google доступ к директиве $rootScope from и не знал о свойстве $root. Спасибо за ответ. - person ivkremer; 28.09.2014
comment
Должен быть правильный ответ... В любом случае спасибо за решение. - person GOSCHEN; 16.06.2016
comment
Твердый раствор. А+ - person dps; 06.12.2017

Не рекомендуется использовать корневую область для установки и получения свойств в вашем угловом приложении. Попробуйте использовать $cacheFactory, так как таким образом вы также можете кэшировать некоторые значения по различным запросам. (документы $cacheFactory)

person Kurt Du Bois    schedule 12.02.2014
comment
Да, я подумал, что использование $rootScope в таком виде — не лучшая идея. Спасибо за предложение кстати. Я ищу лучшие способы создания широко доступных объектов, которые я могу использовать на всем сайте из различных директив. Я считаю, что документация на сайте angular совершенно бесполезна (как и большая часть этого сайта), потому что она ничего не объясняет и не демонстрирует реальный вариант использования или, по крайней мере, логические варианты использования. В моем случае все директивы на сайте должны иметь постоянный доступ к пользовательской информации и некоторым другим битам информации. Лучший способ? Знаете ли вы полезное. хорошая документация может быть? - person GRowing; 13.02.2014
comment
Эй, я нашел полезную информацию, а также этот jmdobry.github.io/angular-cache/ guide.html и полезное видео с YouTube. Спасибо за этот совет! Я очень ценю это :), и я думаю, что рассмотрю это как подход к реальному использованию в том, над чем я работаю. Однако Майк ответил на мой вопрос с объяснением, поэтому я отмечу его ответ как правильный ответ. - person GRowing; 13.02.2014

Иногда мне приходится использовать $scope.$root:

app.directive('setOrdinal', function() {
  return {
    link: function($scope, $element, $attr) {

      var steps = $scope.$root.steps;

      $scope.$watch(setOrdinal, function(value) {
        if (value)
        {
          // steps code here
        }
      });
    }
  };
});

app.controller('stepController', ['$scope', '$rootScope', 'GetSteps', function ($scope, $rootScope, GetSteps) {
  var s = $scope;
  var r = $rootScope;

  s.initialize = function(id)
  {
    GetSteps.get({id: id}, function(resp){
      r.steps = resp.steps;
    });
  };
}]);
person omikes    schedule 05.09.2016
comment
сэкономил мне много времени - person EmptyData; 27.05.2017

Поработав некоторое время над этим же вопросом, я подумал, что стоит отметить то, что было упущено из виду в первом посте. Вот мой исходный код:

app.directive('countrymap', function() 
{
    return {
        link: function(scope, element, attrs) {
            scope.$watch("countryMap", function (newCountry, oldCountry) 
            {
                setTimeout( function() 
                {
                    //function body here    
                }, 100);
            })
        }
    };  
}]);

Помимо более философского вопроса дизайна о том, следует ли вам вообще использовать $rootScope, в моем коде выше есть одна вопиюще неправильная вещь, которая, как мне кажется, была упущена из решения Майка — ссылка на $rootScope. Если вы похожи на меня и разделили свои файлы директив и контроллеров, вам нужно будет изменить свой код следующим образом:

app.directive('countrymap', ['$rootScope', function($rootScope) 
{
    return {
        link: function(scope, element, attrs) {
            $rootScope.$watch("countryMap", function (newCountry, oldCountry) 
            {
                setTimeout( function() 
                { 
                    //function body here
                }, 100);
            })
        }
    };  
}]);

Тем не менее, остается еще один мучительный вопрос: можно ли достичь той же цели, без ссылки на $rootScope в директиве? Действительно можете. Вам необходимо широковещательно передать изменение свойства $rootScope, чтобы все дочерние области знали об изменении и отслеживали это изменение в директиве.

Контроллер:

$rootScope.countryMap = 'thiscountry_map';
$rootScope.$broadcast( "countryMapChanged", $rootScope.countryMap );

Директива:

app.directive('countrymapalt', [function() 
{
    return {
        link: function(scope, element, attrs) {
            scope.$on("countryMapChanged", function(event, map) 
            {
                setTimeout( function() 
                { 
                    //function body here
                }, 100);
            })
        }
    };  
}]);
person user1991179    schedule 07.08.2015

Другой способ — создать службу и передать этой службе доступ к $rootScope и другим функциям. Я сделал это так из-за моего окружения...

app.service('myService', function ($rootScope) 
{
    this.removeItem = function (el) 
    {
       console.log('rootScope: ',$rootScope);
       return true;
    }
});


app.directive('draggable', function($document,myService) 
{
   return function(scope, element, attr) 
   {
        myService.removeItem({id:1})
   }
});

Если вы можете, лучший способ - это решение Майка. если нет, попробуйте мое решение.

person Philip Enc    schedule 21.03.2016