I am having issues getting my directive to render its content only after my promise has been resolved. I thought then()
was supposed to do this but it doesn't seem to be working..
Here is my controller:
// Generated by CoffeeScript 1.6.3
(function() {
var sprangularControllers;
sprangularControllers = angular.module('sprangularControllers', ['sprangularServices', 'ngRoute']);
sprangularControllers.controller('productsController', [
'$scope', '$route', '$routeParams', 'Product', 'Taxonomy', function($scope, $route, $routeParams, Product, Taxonomy) {
Taxonomy.taxonomies_with_meta().$promise.then(function(response) {
return $scope.taxonomies = response.taxonomies;
});
return Product.find($routeParams.id).$promise.then(function(response) {
return $scope.currentProduct = response;
});
}
]);
}).call(this);
My directive:
// Generated by CoffeeScript 1.6.3
(function() {
var sprangularDirectives;
sprangularDirectives = angular.module('sprangularDirectives', []);
sprangularDirectives.directive('productDirective', function() {
return {
scope: {
product: '='
},
templateUrl: 'partials/product/_product.html',
link: function(scope, el, attrs) {
console.log(scope);
console.log(scope.product);
return el.text(scope.product.name);
}
};
});
}).call(this);
Scope returns okay, and when I check it in dev tools scope.product
is not undefined however I am presuming that is because by the time I check it the promise has been resolved?
console.log(scope.product)
however, returns undefined..
As stated in an official thread about this issue (quickly closed as "won't fix because it would make directives wait"), a workaround is to wrap your directive in a ng-if
:
<div ng-if="myPromiseParam">
<my-directive param="myPromiseParam">
</div>
Because your value is asynchronously populated, you'll want to add a watch function that updates your bound element.
link: function(scope, el, attrs) {
scope.$watch('product', function(newVal) {
if(newVal) { el.text(scope.product.name);}
}, true);
}
You could also move a lot of complexity into a directive controller and use the link function for manipulating the DOM only.
The true
third parameter to $watch
causes a deep watch, since you're binding this directive to a model.
Here are a couple of links with good examples:
http://www.ng-newsletter.com/posts/directives.html
http://seanhess.github.io/2013/10/14/angularjs-directive-design.html
I know this is an older question, but thought I would try my hand at providing an updated answer.
When using a router, both ui-router and ngRouter have resolve methods that will resolve promises on url changes before switching to that route and rendering things on the page.
ngRouter Resolve tutorial
ui-router Resolve docs
Another option, instead of using $watch
is to use angulars $q
promise library.
More specifically, the $q.when()
method. This takes promises and values. IF it's a promise it will fire a .then()
when the promise resolves. If its a value, it wraps it in a promise and immediately resolves it.
link: function(scope, el, attrs){
$q.when(scope.product).then(function(product){
scope.product = product;
el.text(scope.product.name);
});
}
Or there a couple way you can not show anything just with html.
<product-directive product='object'>
<!-- Will hide span until product.name exists -->
<span ng-show='product.name'>{{ product.name }}</span>
<!-- Will show default text until key exists -->
{{ product.name || 'Nothing to see here' }}
<!-- Will show nothing until key exists -->
<span ng-bind='product.name'></span>
</product-directive>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With