I'm just learning angularjs and I'm strugling to get the results I want from this factory :
app.factory('foreCast', ['$http', function($http,$scope ) {
var req = $http.jsonp("https://www.kimonolabs.com/api/c1ab8xnw?&apikey=api-key&callback=JSON_CALLBACK");
req.success(function (data) {
req.rows =data.results.collection1;
req.rand =req.rows[Math.floor(Math.random() * req.rows.length)];
console.log(req.rand);
//i want this results
});
return req; //how can i return req.rand?
}]);
app.factory('foreCast', ['$q', '$http', function ($q, $http) {
return {
getRand: function () {
var deferred = $q.defer();
$http
.jsonp("https://www.kimonolabs.com/api/c1ab8xnw?&apikey=api-key&callback=JSON_CALLBACK")
.then(function (response) {
var rows = response.data.results.collection1;
var rand = rows[Math.floor(Math.random() * rows.length)];
deferred.resolve(rand);
}, function (err) {
deferred.reject(err);
})
return deferred.promise;
}
}
}])
And then from controller for exemple use it like this :
foreCast.getRand().then(function(rand){
var myRand = rand;
})
So first of all, you never want to use the success handler with http. I believe its actually getting deprecated. The best practice is to use .then and .catch for errors. Secondly, most of the time you should be processing the result in your controller since the service is not supposed to know what to do with the data.
So that being said, we can trim down your factory a little bit.
app.factory('foreCast', ['$http', function($http,$scope ) {
var factory = {};
factory.rand = function() {
return $http.jsonp("https://www.kimonolabs.com/api/c1ab8xnw?&apikey=api-key&callback=JSON_CALLBACK");
};
return factory;
}]);
Now in your controller:
app.controller('controller', ['foreCast', function(foreCast) {
var self = this;
foreCast.rand().then(function(response) {
var rows = response.results.collection1;
self.rand = rows[Math.floor(Math.random() * rows.length)];
});
}]);
now in your view just access this value with rand.
<div ng-bind="ctrl.rand"></div>
Related
I'm fairly new to angularJS but I've read that services should be singleton. However, it wont' work.
Here is my service:
.factory('TrainingPlan', function($http, SERVER){
var o = {
exercises: [],
planID : 0
};
o.init = function(){
if(o.exercises.length == 0)
return o.getAllExercises();
};
o.getAllExercises = function(){
$http({
method: 'GET',
url: SERVER.url + 'listener.php?request=getAllExercises&planID=' + o.planID
}).then(function(data){
o.exercises = angular.copy(o.exercises.concat(data.data));
console.log("Exercises in Trainingplan Services");
console.log(o.exercises);
return o.exercises;
})
;
};
o.getExercise = function(exerciseID){
for(var i = 0; i < o.exercises.length; i++){
if(o.exercises[i].exerciseID == exerciseID)
{
return o.exercises[i];
}
}
};
return o;
})
And I have two Controllers:
.controller('TrainingDetailCtrl', function($scope, $stateParams, TrainingPlan, $timeout) {
TrainingPlan.init();
$timeout(function(){
$scope.exercises = TrainingPlan.exercises;
$scope.numberOfUnfishedExercises = $scope.exercises.length;
button.innerHTML = "asdf";
}, 250);
})
(I haven't copied the whole controller, but it works so far...)
.controller('TrainingHistoryEditCtrl', function($scope, $stateParams, TrainingPlan, $timeout) {
var exerciseID = $stateParams.exerciseID;
$scope.currentExercise = TrainingPlan.getExercise(exerciseID);
console.log($scope.currentExercise);
})
So actually I go from TrainingDetailCtrl where I have all the exercises of 'TrainingPlan'. However, when I change the sites, TrainingPlan has no exercises anymore when I wont to use them in TrainingHistoryEditCtrl.
That is because your $http issues an async call. Even if you call init, actually when the code runs to the line $timeout(function(){.., the result may not arrive yet.
Please check this demo: JSFiddle. Wait for 10 seconds then the value is not empty.
Solution: return a promise from the factory. Inside the controller use then to pass in callback function.
I'm trying to add a service to my Angular project for the first time and running into issues injecting it within my controller.
I am getting an error of --
TypeError: Cannot read property 'get' of undefined
I'm looking to properly inject the service into the controller and ways I can improve the code for best practices/efficiency.
Thanks for the help!
I have a folder /event in my angular project with the following files --
app.js
controllers.js
directives.js
services.js
app.js file has --
'use strict';
angular.module('vyrt.event', [
'vyrt.event.controllers',
'vyrt.event.services',
'vyrt.event.directives'
]);
services.js file has --
'use strict';
angular.module('vyrt.event.services', []).
service('VyrtEventService', ['$http', function($http) {
var artistId = 0,
artist = '',
events = [],
active_event_idx = 0;
this.get = function(artistId) {
var url = '/api/users/' + artistId + '/';
$http.get(url).success(function(data, status, headers, config) {
artist = data.artist.user;
events = data.artist.events;
active_event_id = data.artist.events[0].id;
});
return artist, events, active_event_id;
}
}]);
finally, the controller has --
'use strict';
angular.module('vyrt.event.controllers', []).
controller('VyrtEventCtrl', ['$scope', function($scope, VyrtEventService) {
console.log(VyrtEventService.get($scope.artistId));
$scope.activeCampaign = function(idx) {
if (idx == VyrtEventService.active_event_idx) return true;
return false;
};
}]);
The problem is that you've forgotten to put 'VyrtEventService' in your dependency list when you define you controller:
.controller('VyrtEventCtrl', ['$scope', /* you need this ==>*/ 'VyrtEventService', function($scope, VyrtEventService) {
console.log('VyrtEventService', VyrtEventService);
$scope.activeCampaign = function(idx) {
if (idx == VyrtEventService.active_event_idx) return true;
return false;
};
}]);
Update
Your get() function has a couple of issues. First, you need to return the $http.get() call itself and then you can call then() in your controller and set the results to a property on your $scope there. Second, you can't return multiple values like that. You would have to return an array of values or an object with your desired values assigned to it.
service
this.get = function(artistId) {
var url = '/api/users/' + artistId + '/';
return $http
.get(url)
.catch(function(error){
// handle errors here
console.log('Error fething artist data: ', error);
});
}
controller
VyrtEventService
.get(artistId)
.then(function(data){
$scope.artist = data.artist.user;
$scope.events = data.artist.events;
$scope.active_event_id = data.artist.events[0].id;
});
$scope.activeCampaign = function(idx) {
return (idx == $scope.active_event_idx);
};
I'm new to AngularJS and am still trying to wrap my head around using services to pull data into my application.
I am looking for a way to cache the result of a $http.get() which will be a JSON array. In this case, it is a static list of events:
[{ id: 1, name: "First Event"}, { id: 2, name: "Second Event"},...]
I have a service that I am trying to use to cache these results:
appServices.service("eventListService", function($http) {
var eventListCache;
this.get = function (ignoreCache) {
if (ignoreCache || !eventListCache) {
eventListCache = $http.get("/events.json", {cache: true});
}
return eventListCache;
}
});
Now from what I can understand I am returning a "promise" from the $http.get function, which in my controller I add in a success callback:
appControllers.controller("EventListCtrl", ["$scope", "eventListService",
function ($scope, eventListService) {
eventListService.get().success(function (data) { $scope.events = data; });
}
]);
This is working fine for me. What I'd like to do is add an event to the eventListService to pull out a specific event object from eventListCache.
appServices.service("eventListService", function($http) {
var eventListCache;
this.get = function (ignoreCache) { ... }
//added
this.getEvent = function (id) {
//TODO: add some sort of call to this.get() in order to make sure the
//eventListCache is there... stumped
}
});
I do not know if this is the best way to approach caching or if this is a stupid thing to do, but I am trying to get a single object from an array that may or may not be cached. OR maybe I'm supposed to call the original event and pull the object out of the resulting array in the controller.
You're on the right track. Services in Angularjs are singeltons, so using it to cache your $http request is fine. If you want to expose several functions in your service I would do something like this. I used the $q promise/deferred service implementation in Angularjs to handle the asynchronus http request.
appServices.service("eventListService", function($http, $q) {
var eventListCache;
var get = function (callback) {
$http({method: "GET", url: "/events.json"}).
success(function(data, status) {
eventListCache = data;
return callback(eventListCache);
}).
}
}
return {
getEventList : function(callback) {
if(eventListCache.length > 0) {
return callback(eventListCache);
} else {
var deferred = $q.defer();
get(function(data) {
deferred.resolve(data);
}
deferred.promise.then(function(res) {
return callback(res);
});
}
},
getSpecificEvent: function(id, callback) {
// Same as in getEventList(), but with a filter or sorting of the array
// ...
// return callback(....);
}
}
});
Now, in your controller, all you have to do is this;
appControllers.controller("EventListCtrl", ["$scope", "eventListService",
function ($scope, eventListService) {
// First time your controller runs, it will send http-request, second time it
// will use the cached variable
eventListService.getEventList(function(eventlist) {
$scope.myEventList = eventlist;
});
eventListService.getSpecificEvent($scope.someEventID, function(event) {
// This one is cached, and fetched from local variable in service
$scope.mySpecificEvent = event;
});
}
]);
You are on the right track. Here's a little help:
appServices.service("eventListService", function($http, $q) {
var eventListCache = [];
function getList(forceReload) {
var defObj = $q.defer(), listHolder;
if (eventListCache.length || forceReload) {
listHolder= $http.get("/events.json", {cache: true});
listHolder.then(function(data){
eventListCache = data;
defObj.resolve(eventListCache);
});
} else {
defObj.resolve(eventListCache);
}
return defObj.promise;
}
function getDetails(eventId){
var defObj = $q.defer();
if(eventId === undefined){
throw new Error('Event Id is Required.');
}
if(eventListCache.length === 0){
defObj.reject('No Events Loaded.');
} else {
defObj.resolve(eventListCache[eventId]);
}
return defObj.promise;
}
return {
eventList:getList,
eventDetails:getDetails
};
});
Then, in your controller, you handle it like this:
appControllers.controller("EventListCtrl", ["$scope", "eventListService",
function ($scope, eventListService) {
var eventList = eventListService.getList();
eventList.then(function(data){
$scope.events = data;
});
$scope.getEventsList = function(reloadList){
eventList = eventListService.getList(reloadList);
eventList.then(function(data){
$scope.events = data;
});
};
$scope.getEventDetails = function(eventID){
var detailsPromise = eventListService.getDetails(eventID);
detailsPromise.then(function(data){
$scope.eventDetails = data;
}, function(reason){
window.alert(reason);
});
}
}
]);
This way, your events are loaded when the controller first loads, and then you have the option to request a new list by simply passing in a boolean. Getting event details is also handled by an internal promise to give you some error handling without throwing a disruptive error.
I want bind the values from WCF service to controller. but am not able to bind the values from WCF result. but if i use online webservice means its working perfectly.
please help me. i wasted lots of time. i share the code and screen which is worked.
This is My HTML Code.
<div ng-controller = "fessCntrl">
<ul><li ng-click="alertSwap()">click </li></ul>
<ul><pre>data {{data|json}}</pre></ul>
</div>
This is my Angular JS Code
var fessmodule = angular.module('myModule', ['ngResource']);
fessmodule.controller('fessCntrl', function ($scope, stockData) {
$scope.alertSwap = function () {
stockData.query('somedata')
.then(function (result) {
$scope.data = result.data;
}, function (result) {
alert("Error: No data returned");
});
}
});
fessmodule.$inject = ['$scope', 'Data'];
fessmodule.factory('stockData', ['$http', '$q', function ($http, $q) {
var factory = {
query: function (value) {
// here you can play with 'value'
var data = $http.get('http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20(%22YHOO%22)%0A%09%09&env=http%3A%2F%2Fdatatables.org%2Falltables.env&format=json');
var deferred = $q.defer();
deferred.resolve(data);
return deferred.promise;
}
}
return factory;
}]);
This is perfectly working Online webservice.
This my webservice which is not working my WCF Service.
try this
query: function (value) {
// here you can play with 'value'
var data =[];
**$http.get('http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20(%22YHOO%22)%0A%09%09&env=http%3A%2F%2Fdatatables.org%2Falltables.env&format=json').success(response)
{
data = response;//Or value=response.Data;
};**
var deferred = $q.defer();
deferred.resolve(data);
return deferred.promise;
}
Instead of your's ..
How would I handle loading data from a service before a page loads exactly?
I've tried to use resolve but the problem is that the service that I need to call hasn't been created yet so I would have to do all of the service logic in the resolve function, which I don't really want to do.
I currently have a working way of handling it, but of course there's the delay between when the view content is loaded and when the service has actually returned the data needed to populate:
myApp.service('WorkshopGetStoreState', ['Transaction', 'ExpServices', 'CacheService', function(Transaction, ExpressServices, CacheService) {
return {
submit:function(defer) {
var requestTemplate = ExpServices.getRequestTemplate('WorkshopGetStoreState');
var request = requestTemplate.template;
var params = {};
params.action = "getStoreAddress";
params.locationInfo = [{'storeId': '004141' }];
for (var attrname in params) {
request.service.serviceRequest[attrname] = params[attrname];
}
Transaction.submit(requestTemplate.url, request, defer);
return defer.promise;
}
};
}]);
myApp.factory('WorkShopFlowService',['WorkShopGetStoreState', function(WorkshopGetStoreState) {
var address={};
return {
getStoreAddress : function() {
return address;
},
setStoreAddress : function(addressParam) {
address = addressParam;
},
init : function(defer){
var promise = WorkshopGetStoreState.submit(defer);
return promise;
}
};
}]);
myApp.controller('WorkshopLandingCtrl', [ '$scope', 'WorkShopFlowService', '$q', function($scope, WorkShopFlowService, $q) {
var defer = $q.defer();
var storedAddress = WorkShopFlowService.getStoreAddress();
if (storedAddress) {
$scope.address = storedAddress;
}
else {
WorkShopFlowService.getDefaultLocation(defer).then(function(result) {
$scope.address = result.serviceResponse.storeInfo[0];
WorkShopFlowService.setStoreAddress($scope.address);
});
}
}]);
Edit: It seems that there is now support for referencing objects as string names in the newer version of AngularJS so now doing it in a resolve is the way to do it.