Inject Service into Directive AngularJS and data binding. - javascript

I created a Service that obtain data with $http and this data is stored in a variable of this Service, also I created a Directive that use the service to create a tag select with options, these options were obtained in the service, but this is my problem the data obtained never connect with directive.
Service and Directive:
angular.module('myModule'[])
.factory('myService', ['$http', function($http){
var listOptions = [];
$http({
method: 'GET',
url: 'urlToDataJson'
}).then(function(resp){
listOptions = resp.data
})
;
return {
list: listOptions;
}
}]
.directive('myDirective', ['myService', function(myService){
restrict: 'E',
template: '<select ng-options="item.id as item.name for item in list"></select>',
replace: true,
controller: ['$scope', function($scope)
$scope.list = MyService.list;
]
}])
;
with the Chrome's DevTool I can see data is updated after $http runs, but the data not shown in the options.
The code above is an example that I need to do.

Your $http call returns a promise object. Wrap the $http call in a function and return the promise object, then, in your directive, invoke this function and resolve the promise object and get the data.
Specifically,
getData(){
return $http({
method: 'GET',
url: 'urlToDataJson'
}).then(function(resp){
listOptions = resp.data
); // this returns a promise
}
And then in your directive, resolve the promise like so:
MyService.getData().then(function(data){
console.log(data); // <-- this is how you access the result of your $http call
});

You can do this also ,
return $q(function (resolve, reject) {
$http({
method: 'GET',
url: 'urlToDataJson'
}).then(function(resp){
$scope.responseDate = resp.data;
resolve(responseData);
});
});

Related

Passing information previously retrieved to templateProvider in AngularJS

I'm using AngularJS 1.3 and UI-Router. I have an state in which i have a resolve and a templateProvider.
What i'm trying to accomplish is that the information retrieved from database in the resolve can be used by the templateProvider. Right now, I have to get the information twice, once from resolve and another from templateProvider, and that's annoying.
The code:
.state('articleurl', {
url: '/:articleUrl',
resolve: {
article: function ($http, $stateParams, $location) {
return $http({
method: 'GET',
url: '/articles/' + $stateParams.articleUrl
})
.then(function (article) {
return article;
}, function (error) {
$location.path('/404');
});
},
loggedin: checkLoggedin
},
templateProvider: ['$templateFactory', '$stateParams', '$http', function ($templateFactory, $stateParams, $http) {
return $http({
method: 'GET',
url: '/articles/' + $stateParams.articleUrl
}).then(function(article) {
if ( article.data.template )
return $templateFactory.fromUrl('articles/views/templates/' + article.data.template + '.html');
else
return $templateFactory.fromUrl('articles/views/templates/news.html');
});
}],
controller: 'ArticlesViewController'
})
As you can see, according to article's kind i load a different template in the templateProvider. Besides, i use the article's information in the controller which has been previously got in the state's resolve.
Is there any way to use in the templateProvider the information previously fetched in the resolve avoiding this way another call to database?
Right now, it is doing 2 calls to database per connection...
Thanks!
app.factory('article', function ($cacheFactory){
var articleCache = $cacheFactory('article');
return function (url) {
return articleCache.get(url) || articleCache.put(url, $http({
method: 'GET',
url: '/articles/' + url
})
);
};
});
Use it as article($stateParams.articleUrl).then(...) in both places, that will keep the things DRY. You may get better control over the cache (e.g. expiration) by replacing $cacheFactory with angular-cache.
$http own caching may be successfully used as well instead of explicit caching:
If there are multiple GET requests for the same URL that should be
cached using the same cache, but the cache is not populated yet, only
one request to the server will be made and the remaining requests will
be fulfilled using the response from the first request.
I think you can inject directly the resolved variables, so you could inject article in templateProvider:
.state('articleurl', {
url: '/:articleUrl',
resolve: {
article: function ($http, $stateParams, $location) {
return $http({
method: 'GET',
url: '/articles/' + $stateParams.articleUrl
})
.then(function (article) {
return article;
}, function (error) {
$location.path('/404');
});
},
loggedin: checkLoggedin
},
templateProvider: ['$templateFactory', '$stateParams', '$http', 'article', function ($templateFactory, $stateParams, $http, article) {
// Now here you can use article without the need to re-call it
}],
controller: 'ArticlesViewController'
})

service that run $http for controllers

I have multiple controllers that need to use my custom service which use $http. I did something like this
.service('getDB', function($http){
return {
fn: function(){
return $http({
url: "http://example.com",
method: "GET"
});
}
}
})
.controller('myCtrl', function($scope, getDB) {
console.log(getDB.fn());
}
In my console.log of getDB.fn() I see $promise, how can I get the response data?
$http returns a promise. Its implementation can be understood here :
$q
In order to use your promise, you have to do the following :
.controller('myCtrl', function($scope, getDB) {
getDB.fn(something).then(function(result){
// The result can be accessed here
}, function(error){
//If an error happened, you can handle it here
});
}
here is the way you can pass parameters :
.service('getDB', function($http){
return {
fn: function(something){
return $http({
url: "http://example.com/" + something,
method: "GET"
});
}
}
})

How to get json data in my case?

I am trying to use httml get to get the json
I have something like
.controller('testController', function($scope, $state, $http) {
$http({
url: "/json/test.json",
method: "GET",
}).success(function(data) {
$scope.testData = data;
console.log(data)
});
//outside of the $http scope but under the same controller, I have
//It shows undefined.
console.log($scope.testData)
})
I know we have to keep data our of the login codes so I don't want to modify the data inside the $http. Is there anyway to accomplish this? Thanks!
First, don't put this in a controller. Move it to a Service. That's what Services are designed for.
Second, the $http service is asynchronous. Your result only exists in the success callback, and your console.log will be called before the http request is finished. You need to assign it to a scope variable to use it outside of the callback, and expect it to be empty until the call back is complete.
http://blog.brunoscopelliti.com/deal-with-users-authentication-in-an-angularjs-web-app provides an example of an AngularJS authentication service, if that's what you're doing.
To go with your example:
.controller('testController', function($scope, $state, $http) {
$scope.testData = {};
$http({
url: "/json/test.json",
method: "GET",
}).success(function(data) {
$scope.testData = data;
$scope.logData();
});
$scope.logData = function() {
console.log($scope.testData);
}
});
This plnkr code is created in order to give your answer, yes you can have the $scope.testData outside the http request.
Have a look!!
var app = angular.module('plunker', []);
app.controller('testController', function($scope, $http) {
$http({
url: "test.json",
method: "GET",
}).success(function(data) {
$scope.testData = data;
alert(data);
callA();
});
function callA(){
alert($scope.testData);
}
});

returning value to higher scope inside from a chained functions in angular js

I have a function getUsers that I want to return JSON from an web api .. but I cant seem to get the data out, I can't return the data because the function is inside $http. What should i do ?
function getUsers() {
$http({ method: 'GET', url: '/api/loginapi/userdetails' })
.success(function (data, status, headers, config) {
details = data;
});
return details;
}
$http makes an asynchronous call, so you can't immediately return fetched data.
What you can return is a promise. Good news, $http() returns one:
function getUsers() {
return $http({ method: 'GET', url: '/api/loginapi/userdetails' });
}
Then you can use your function:
getUsers().then(function(data) {
var details = data;
// Process your details!
});
You can access data there for sure, nothing is 'inside' $http, I suggest you pass in a callback to getUsers() and do whatever you want with the returned data:
var getUsers=function(callback){
$http({ method: 'GET', url: '/api/loginapi/userdetails' })
.success(function (data, status, headers, config) {
callback(data);
});
}
and use it like this inside your controller:
getUsers(function(users){
$scope.whatever = users;
})
I created plunkr for your question http://plnkr.co/edit/lqX4apmvnKM3i5jGZDQM?p=preview
$http return a promise. Please read details about promise at http://johnmunsch.com/2013/07/17/angularjs-services-and-promises/ . It is an important understanding if you want to write asynchronous application. This is another useful link - Inside my own Angular service, how do you get the return value back to the Controller that called the service? . Refer to answer. It explains how to use promise and deffered in angularjs.
var app = angular.module('plunker', []);
app.service('UserService', ['$http', '$q',
function($http, $q) {
this.getUser = function() {
return $http({
method: 'GET',
url: 'data.json'
});
};
}
]);
app.controller('MainCtrl', function($scope, UserService) {
$scope.user = {};
UserService.getUser().then(function(response){
$scope.user = response.data;
});
});

unable to get data from $q into scope

I'm trying to bind some data being returned from an API to my scope using promises with $q, I am able to pull the data from the server without any issue (I can see JSON being returned using fiddler) however the $scope variable remains empty, any help would be greatly appreciated! Thanks in advance.
Code:
toDoListService.js
app.factory("toDoListService", function ($http, $q) {
var deferred = $q.defer();
return {
get: function () {
$http({ method: 'GET', url: '/api/todo/' }).
success(function (data) {
deferred.resolve(data);
}).
error(function (data, status, headers, config) {
deferred.reject(status);
});
return deferred.promise;
}
});
toDoListController.js
app.controller("toDoListController", function($scope, toDoListService){
$scope.toDoList = toDoListService.get();
});
First of all you should put var deferred = $q.defer(); in your get function, so that every get has it's own deferred object.
Second what get actually returns is a promise. So you need to access you data in this way:
app.controller("toDoListController", function($scope, toDoListService){
toDoListService.get().then(function(data){
$scope.toDoList = data;
});
});
Right now, your $scope.toDoList is bound to a promise. This means of binding used to work, but was deprecated in, I think, 1.2.
As Michael suggests, you must do:
app.controller("toDoListController", function($scope, toDoListService){
toDoListService.get().then(function(data){
$scope.toDoList = data;
});
});
Also, using $q is not required here at all, as $http returns a promise anyway. Therefore, you could just do:
app.factory("toDoListService", function ($http){
return {
get: function () {
return $http({ method: 'GET', url: '/api/todo/' });
}
};
});
You can simplify your code by using this:
toDoListService.js
app.factory("toDoListService", function ($http, $q) {
return {
get: function () {
return $http({ method: 'GET', url: '/api/todo/' });
}
}
});
toDoListController.js
app.controller("toDoListController", function($scope, toDoListService) {
toDoListService.get().then(function(response){
$scope.toDoList = response.data;
return response;
});
});
Be sure to return response in your success callback, otherwise chained promises would not receive it.

Categories

Resources