Issue AngularJS directive only after defining $ scope.myVar

When my "AngularJS" page loads, I retrieve some data from the server and set it to the scope:

myApp.controller('somePage', ['$scope', 'User', '$routeParams', function($scope, User, $routeParams){ // Get the user. User.get('1234').then(function(user){ $scope.user = user; }); }); 

On my page, I have a directive that needs the definition of $scope.user .

 <div> <user-profile-info></user-profile-info> </div> 

Directive:

 myApp.directive('addActionButton', function() { return { scope: false, link: function(scope, element, attrs){ element.bind('click', function(){ alert(scope.user.name); }); }, template: '<button id="foo">Say hi to {{ user.name }}</button>' }; }) 

The page currently displays the component up to $scope.user , so there are errors.

How can I make this directive only render when $scope.user ? Or how can I make a page view only rendering when the controller receives its data?

EDIT: all of the above code is greatly simplified, so you do not need to read additional information, but still there are restrictions that I need for the component (for example, a link, a template with an attribute, an area with ajax call).

+6
source share
2 answers

ng-if is for this purpose:

 <user-profile-info ng-if="user"></user-profile-info> 

See this example:


 angular.module('myApp', []) .controller('somePage', ['$scope', '$timeout', function($scope, $timeout){ // Get the user // simulating delayed request, 3 secs $timeout(function(){ $scope.user = { name: 'Shomz' }; }, 3000); }]) .directive('userProfileInfo', function() { return { restrict: 'E', link: function(scope, element, attrs){ element.bind('click', function(){ alert(scope.user.name); }); alert(scope.user.name); // this would throw an error without ng-if }, template: '<button id="foo">Say hi to {{ user.name }}</button>' }; }) 
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <div ng-app="myApp" ng-controller="somePage"> <p ng-hide="user">Waiting for user data...</p> <user-profile-info ng-if="user">qwe</user-profile-info> </div> 
+6
source

I think you are more concerned with processing inside the directive too soon, rather than rendering the directive. You can set up a two-way binding and attach a promise, or you can use eventing to let the directive know to start, or you could set the data timeout before initializing the directive process. The main idea is not to write processing code inside a direct link. It’s also nice to have a controller associated with the directive and run the init function in the directive controller after you receive the data.

A simple example with both a one-time and a promise.

 .directive('userProfileInfo', function($q){ return{ /*Your configuration*/, scope:{user:"="}, link: function linker(scope, elm, attrs){ /* Promise way */ //Set up data or promise, q.when will make sure it is always a promise, be careful about not setting values like null etc.. $q.when(scope.user).then(init); /* One time watch way */ var unwatch = scope.$watch('user', function(user){ if(angular.isDefined(user)){ unwatch(); //Remove the watch init(); //initialize } }); function init(){ //Initialize directive processing accessing scope.user } } } }); 

and bind it like:

 <user-profile-info user="user"></user-profile-info> 

If you use one timer, keep the code as is if you use the promised approach. bind a promise, i.e.

In your controller:

  $scope.userPromise = User.get('1234'); 

and

  <user-profile-info user="userPromise"></user-profile-info> 

And if you are worried that you did not specify a directive, just use ng-if in the directive element if your directive priority is less than ng-ifs, which it will not display.

+2
source

Source: https://habr.com/ru/post/981893/


All Articles