smdufb smdufb - 21 days ago 6
AngularJS Question

Calling controller function from directive does not update scope

I made a directive using a service and $resource to search a REST API and pass the result to a controller. The code looks like this:

app.controller('productsCtrl', ['$scope', function ($scope) {
var self = this;
self.selection;

self.searched = function (selected) {
self.selection = selected;
};
}]);

app.service('productsService', ['productsResource', function (productsResource) {
var self = this;

self.findProducts = function (search) {
return productsResource.query({
sku: search
});
};
}]);

app.factory('productsResource', ['$resource', function ($resource) {
return $resource('products/:sku', {
id: '@sku'
});
}]);

app.directive('productSearch', ['productsService', function (productsService) {
return {
restrict: 'E',
scope: {
productSelected: '&'
},
templateUrl: '/products/product_search.html',
link: function (scope) {
scope.findProducts = function (search) {
scope.searchResults = productsService.findProducts(search);
};
scope.selectResult = function (selected) {
scope.selection = selected;
scope.showResults = false;
};
}
};
}]);


The relevant HTML lines are:

<div ng-show='products.selection'>
{{products.selection.name}} //does not update
</div>


and from the directives template:

<div ng-click="productSelected({selected: selection})"></div>


The problem is my model does not update when the directive calls the controller method (it will show the results of the last search). It sort of makes sense to me because no "angular" function is being called in there. But how am I supposed to get this to work. I've tried with
$scope.$apply()
but that throws an error.

As a side question. Is the way I'm doing it right? Is this the angular way? Especially using a service inside the directive and passing things from the directive to a controller?

EDIT:
This is the whole HTML file (using controllerAs):

<div>
<product-search product-selected='products.searched(selected)'></product-search>
<div ng-show='products.selection'>
{{products.selection.name}}
</div>
</div>

Answer

I think you are missing the callback from directive. You might need to add

scope.productSelected({selected: selection})

inside the scope.selectResult function in directive. The full code will look like this

 scope.selectResult = function (selected) {
     scope.selection = selected;
     scope.showResults = false;
     scope.productSelected({selected: selected}); // add this
 };