angular directive handles http request - angularjs

I have angular directive that accept url to obtain remote data:
<my-tag src="http://127.0.0.1/srv1">...
Directive itself:
app.directive('myTag', ['$http', function($http) {
return {
restrict: 'E',
transclude: true,
replace: true,
//template: '<div ng-repeat="imgres in gallery">{{imgres.isUrl}}\'/></div>',
scope:{
src:"#", //source AJAX url to dir pictures
},
controller:function($scope){
console.info("enter directive controller");
$scope.gallery = [];
$http.get($scope.src).success(function(data){
console.info("got data");
$scope.gallery.length = 0;
$scope.gallery = data;
});
}
}
In general it works and I can see in FireBug console:
enter directive controller
GET http://127.0.0.1/srv1
got data
But If I'm placing second instance of directive bind to another url:
<my-tag src="http://127.0.0.1/srv2">...
Works only one with following log:
enter directive controller
GET http://127.0.0.1/srv1
enter directive controller
GET http://127.0.0.1/srv2
got data <-- as usual it relates to first directive
Couldn't you help me what is wrong with 2 directive nstances

First of all I don't see any problem. You use directive several times therefore isolate scope is right way.
I just changed src:"#" to src:"=".
Demo Fiddle
HTML
<div ng-controller = "fessCntrl">
<my-tag src="'http://maps.googleapis.com/maps/api/geocode/json?address=Singapore, SG, Singapore, 153 Bukit Batok Street 1&sensor=true'"></my-tag>
<my-tag src="'http://maps.googleapis.com/maps/api/geocode/json?address=Singapore, SG, Singapore, 3 Bukit Batok Street 1&sensor=true'"></my-tag>
</div>
JS
app.directive('myTag', ['$http', function($http) {
return {
restrict: 'E',
transclude: true,
replace: true,
scope:{
src:"="
},
controller:function($scope){
console.info("enter directive controller");
$scope.gallery = [];
console.log($scope.src);
$http({method: 'GET', url:$scope.src}).then(function (result) {
console.log(result);
}, function (result) {
alert("Error: No data returned");
});
}
}
}]);

Related

AngularJS issue with http get result

I have the following code:
app.controller('carouselCtrl', ['$scope', '$http', function($scope, $http){
$http.get('/app/ajax/get-favs.php').then(function(response){
$scope.slides = response.data;
});
}]);
app.directive('slider', function($timeout) {
return {
restrict: 'AE',
replace: true,
scope: {
slides: '='
},
link: function(scope, elem, attrs) {
scope.currentIndex=0;
[...]
scope.$watch('currentIndex', function(){
scope.slides.forEach(function(slide){
slide.visible=false;
});
scope.slides[scope.currentIndex].visible=true;
});
},
templateUrl: '/app/includes/slider.html'
};
});
My browser console returns:
Error: scope.slides is undefined
.link/ [...] in line 55 (scope.slides.forEach....)
But if I write the $scope.slides object manually instead getting with $http.get the app works correctly. In other words, I can't call the scope.slides object from directive in scope.$watch.
What's wrong?
When you initialize the page, scope.slides doesn't exist yet (= it's undefined). It will only get a value once the api call is complete. Add a check for the existence of scope.slides in your directive:
scope.$watch('currentIndex', function(){
if (!scope.slides) return; // Added row
scope.slides.forEach(function(slide){
slide.visible=false;
});
scope.slides[scope.currentIndex].visible=true;
});

How can I use both $http and $timeout in AngularJS directive?

This is a part of my codes
Object_Angular.directive("ntgChangeScanInnerHtmlWorkshop", ["$timeout", function($timeout){ ...
But I need to also get access to $http since I want to load things from my API. How can I do this?
What I have is a display of _ids in a <p></p>. Let say I have <p>{{collections._id}}</p>. I want that <p></p> to display the name field (collections.String_Name) not the _id. So I think to take the inner HTML of the <p>{{collections._id}}</p> after the value loads and then GET the String_Name from the API via { _id: innerHTMLValueOfP } then in .success I do set back the inner value with result.String_Name. Hence I need to have $http and $timeout in my directive to achieve this.
Example of using $http in directive
app.directive('myTag', ['$http', function($http) {
return {
restrict: 'E',
transclude: true,
replace: true,
scope:{
src:"="
},
controller:function($scope){
console.info("enter directive controller");
$scope.gallery = [];
console.log($scope.src);
$http({method: 'GET', url:$scope.src}).then(function (result) {
console.log(result);
}, function (result) {
alert("Error: No data returned");
});
}
}
}]);
or
app.directive('example', function( $http){
return {
restrict:'E',
link: function($scope,$element,$timeout){
$http.post('/example', {
data
}).success(function(data){
}).error(function(data){});
}
});

2 way binding not working on directive in isolated scope

I'm just trying to do a simple directive, but for some reason the 2 way data binding isn't working in my directive. From my code you can see that a console log in the directive that will read the correct information I have in the $scope.displayMaintenance variable, but I can't change it in my directive.
HTML:
<maintenance-banner display-maintenance="displayMaintenance"></maintenance-banner>
Controller:
$scope.displayMaintenance = false;
$scope.$watch('displayMaintenance', function(data) {
console.log("i changed!: " + data);
});
Directive:
.directive('maintenanceBanner', function() {
return {
restrict: 'E',
replace: true,
scope: {
displayMaintenance: '='
},
templateUrl: '/partials/navbar/maintenance-banner.html',
link: function(scope) {
console.log(scope.displayMaintenance);
scope.displayMaintenance = true;
}
};
})
Any suggestions?
The issue may be that you use your directive inside another isolated scope.
I have created a sample: http://jsfiddle.net/2063n7te/
changing the model value using assignment replaces the model object which may not be reflected in the parent scope.
in short: do not bind primitives directly to the scope.
instead of
$scope.text = "foo";
use
$scope.input = {
text: "foo"
};
a good read is: http://www.thinkingmedia.ca/2015/01/learn-how-to-use-scopes-properly-in-angularjs/
point #4 applies specifically to the behaviour you are seeing.
Check that your directive can find the template URL.
Works for me:
var app = angular.module('app',[]);
app.controller('ctrl', function($scope) {
$scope.displayMaintenance = false;
$scope.$watch('displayMaintenance', function(data) {
alert("i changed!: " + data);
});
});
app.directive('maintenanceBanner', function() {
return {
restrict: 'E',
replace: true,
scope: {
displayMaintenance: '='
},
template: '<div>{{displayMaintenance}}</div>',
link: function(scope) {
console.log(scope.displayMaintenance);
scope.displayMaintenance = true;
}
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<maintenance-banner display-maintenance="displayMaintenance"></maintenance-banner>
</div>

How to deal with more than one scope in an Angular directive?

Using directives I ended stuck when I needed to have more than one scope.
I'm building a data visualization app with Mongoose Node, Express and D3JS.
Here's the directive
angular.module('prodsChart', [])
.controller('businessCtrl', ['$scope','$http', 'BusinessSrv', 'Products', function($scope, $http, $location, BusinessSrv, Products) {
Products.get()
.success(function(data) {
$scope.products = data;
});
BusinessSrv.getTotal()
.success(function(data) {
$scope.businessSales = data;
});
}])
.directive( 'saleProd', [
function () {
return {
restrict: 'E',
link: function (scope, element) {
// Building the chart here
}
And the HTML :
<sale-prod></sale-prod>
Is it good to inject that way the Services in the Directive ?
Now I have 2 set of data in two $scope.
How do I use them in the directive ?
You can inject the $rootScope into your directive:
angular.module('prodsChart', [])
.directive( 'saleProd', ['$rootScope', function ($rootScope) {
// your code here
}]);
and then use it everywhere within the directive.
In 1st and 2nd example directive is in controller's scope and controller's datasets transferred to the directive as attributes. In 1st example directive can modify controller's data. In 2nd example directive use controllers data as strings and creates 2 objects 'productsObj' and 'salesObj' and can't modify parent's scope. It depends on how you handle attributes in the directive and how to transfer them into it. Just click on items in 'Product list (directive)' section and you'll see result.
1st: http://plnkr.co/edit/v46oEGHvUnxMNYsKAeaW?p=preview
var directive = function() {
return {
restrict: 'E',
replace: true,
templateUrl: 'directive-template.html',
scope: {
products: '=',
sales: '='
}
};
};
html:
<div ng-controller="BusinessController as BusinessCtrl">
<sale-prod products="BusinessCtrl.products" sales="BusinessCtrl.sales"></sale-prod>
</div>
2nd: http://plnkr.co/edit/7CyIsqBNLbeZjyfbkGo9?p=preview
var directive = function() {
return {
restrict: 'E',
replace: true,
templateUrl: 'directive-template.html',
scope: {
products: '#',
sales: '#'
},
link: function(scope, element, attrs) {
attrs.$observe('products', function(newVal) {
scope.productsObj = angular.fromJson(newVal);
});
attrs.$observe('sales', function(newVal) {
scope.salesObj = angular.fromJson(newVal);
});
}
};
};
html:
<div ng-controller="BusinessController as BusinessCtrl">
<sale-prod products="{{BusinessCtrl.products}}" sales="{{BusinessCtrl.sales}}"></sale-prod>
</div>
3rd example is just a piece of code that show's how to inject service in directive and controller. I add it because in you example i didn't see service injection in directive:
(function(undefined) {
var app = angular.module('prodsChart', []);
var controller = function($scope, Business, Products) {
// controller logic
};
var directive = function(Business) {
return {
restrict: 'E',
link: function(scope, element, attrs) {
// here you can use all Business service logic
}
};
};
var serviceBusiness = function() {
// business service logic
};
var serviceProducts = function() {
// products service logic
};
app.controller('BusinessController', ['$scope', 'Business', 'Products', controller])
.directive('saleProd', ['Business', directive])
.service('Business', serviceBusiness)
.service('Products', serviceProducts);
})();
html:
<div ng-controller="BusinessController as BusinessCtrl"></div>
<sale-prod></sale-prod>
You could inject a Service into a directive and use it to bring data across the application or use $emit.
A less elegant solution would be using a .value() and deal with it everywhere in your application.

angularjs: What is the preferred way to pass data from controller to directive(s)?

i have a Article Item page that is composed of several re-usable directives. one section of the page has several of these directives that make the main article for the page.
<div data-ng-controller="ArticleItemController">
<article-breadcrumb data-bread-crumbs="model.breadCrumbs"></article-breadcrumb>
<article-title data-title="model.title"></article-title>
<div id="home-main">
<div id="post-area">
<social-box></social-box>
<article-content-area data-content="model.content"></article-content-area>
<article-author-info data-author="model.author"></article-author-info>
<article-tags data-tags="model.tags"></article-tags>
<social-box></social-box>
</div>
<prev-next-article data-articles="model.prevNextArticle"></prev-next-article>
<related-article data-articles="model.relatedArticles"></related-article>
<comments data-comments="model.comments"></comments>
</div>
</div>
my controller to gets the promise, then i pass parts of model to my directives via attributes.
app.controller('ArticleItemController', function ($scope, genApi)
{
$scope.model = $scope.model || {};
genApi.Articles.get({ Id: 60 }).$promise.then(function (data) {
$scope.model = data;
});
});
but this doesn't seem to work or it's sometimey. the only way i can see the data from the directives is if i do this and force the $apply.
app.directive('articleBreadcrumb', function ($timeout)
{
return {
restrict: 'EA',
replace: true,
scope: { breadCrumbs: '=' },
templateUrl: '/app/directives/articleItem/articleBreadcrumb/articleBreadcrumb.html',
link: function (scope) {
$timeout(function() {
$timeout(function () {
console.log(scope.breadCrumbs);
}, 0);
},0);
}
};
});
what are some better ways of doing this?
Your way of thinking is right, indeed the best way to pass data to your directives is using attributes, or if your directive is very simple you can even inherit the data from your parent scope.
Here are 2 example directives, one for each case:
app.directive('myScopedDirective', function() {
return {
restrict: 'E',
scope: {content: '='},
replace: true,
template: '<div>{{content}}</div>'};
});
app.directive('myInheritedDirective', function() {
return {
restrict: 'E',
replace: true,
template: '<div>{{content}}</div>'};
});
And here is a working plunkr demonstrating the promise resolving:
http://plnkr.co/edit/a1MDQpjtWAfTYfLpiypC?p=preview
Hope that helps

Resources