27

So I'm working with the component based approach in angular, lets say I have A directive called <home></home>;

import template from  './home.html';
import controller from './home.controller.js';

angular.module('myApp')
   .directive('home', homeDirective);

let homeDirective = () => {
    return {
        restrict: 'E',
        template, 
        controller,
        controllerAs: 'vm',
        bindToController: true
    };
};

Now I'm able to use the component <home></home> in my routing as follow:

angular.module('myApp')
    .config(($routeProvider) => {
        $routeProvider.when('/', {
            template: '<home></home>'
        })
    })

I really like this approach, but with the "old" approach I was used to using "resolve" in my routeconfig to render the component only when a promise was resolved:

angular.module('myApp')
    .config(($routeProvider) => {
        $routeProvider.when('/', {
            templateUrl: './home.html',
            controller: './home.controller.js',
            resolve: {
            message: function(messageService){
                return messageService.getMessage();
            }
        })
    })

Question

How can I use resolve with a component based approach in angular? aaj

1
  • You pointed one big issue in angular route system. locals (resolves ) are only passed to the route controller. If no controller is specified, the resolves will be fetched before route resolution but there are no way to access them in the template... Best workaround will be to use a service to fetch your resolves and await them in your directive's link or directive's controller init... Commented Dec 2, 2015 at 14:20

3 Answers 3

16
+50

There is a closed issue about that: support resolve option for directives.

The conclusion is that they don't want arbitrary directives being loaded asynchronously, because it would cause too much flicker.

The good news is that Angular 2 supports this (and much more) at the DI layer in a way that's cohesive and doesn't introduce a ton of additional complexity.

In Angular 1.x you could attribute the directive with some information from where the message is to be obtained, and handle the asynchronous loading in your controller. This way you can show some nice loader screen too.

angular.module('myApp')
    .config(($routeProvider) => {
        $routeProvider.when('/', {
            template: '<home my-datasource="feed1"></home>'
        }).when('/other', {
            template: '<home my-datasource="feed2"></home>'
        })
    })
    .factory('DataSources', (messageService) => {
        return {
            feed1: messageService.getMessage,
            feed2: messageService.getError
        };
    });

Or, if you want message to be from always the same source, you can burn messageService.getMessage().then(...) into your controller.

If you don't want the directive to be visible at all before the promises resolve, you can introduce a scope variable initially set to false and then set it to true on resolution, e.g.:

app.controller('HomeController', ($scope, messageService) => {
   $scope.loaded = false;
   messageService.getMessage().then(message => {
       ...
       $scope.loaded = true;
   });
   ...
});

and hide the directive until loaded with ng-if="loaded" at the root element. Yes, that is a bit too much user code, but you have control over everything at least.

Sign up to request clarification or add additional context in comments.

Comments

1

As it turns out, the angular $routeProvider passes the resolved locals on to the $routeChangeSuccess event (nextRoute.locals). So you could create a service that listens for route changes and exposes the locals:

angular.module('myApp', ['ngRoute'])
.factory('$routeLocals', function($rootScope) {
  var locals = {};
  $rootScope.$on('$routeChangeSuccess', function(_, newRoute) {
    angular.copy(newRoute.locals, locals);
  });
  return locals;
})
.run(function($routeLocals) {});

Then you can inject $routeLocals into your directive and use them.

Example: http://codepen.io/fbcouch/pen/eJYLBe

https://github.com/angular/angular.js/blob/master/src/ngRoute/route.js#L614

Comments

1

In Angular 1.x when some data comes to my directive bindings('=') from ajax and more over i watch this bindings in directive, i have not rendered directive right way. I check a lot of stackoverflow topics and blogs and all they writes about data bindings and watch, but it not help me, i saw with my own eyes that sometime directive not rendered but data came.

Only resolve in the directive parent controller helps me in this situation, because in other cases its looks like undefined behavior. I log from my directive, data setup ok, but directive not rendered!(in simple case i am not use ng-if or ng-show to hide it).

You can read more here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.