I'm new to Angular JS and struggling to get a factory to return data when my URL has changed.
In my app config I have:
.state('app.sessionActivity', {
url: "/session/:sessionid/activity/:id",
views: {
'menuContent' :{
templateUrl: "templates/activity.html",
controller: 'SessionActivityCtrl'
}
}
})
My Controller:
.controller('SessionActivityCtrl', ['$scope', '$stateParams', 'localJSONData', function($scope, $stateParams, localJSONData) {
var activityID = $stateParams.id;
var activityVideoURLSRC = null;
localJSONData.getJSONData()
.success(function(data){
$scope.activityData = data[activityID - 1];
});
}])
My factory:
.factory('localJSONData', ['$http', '$stateParams', function($http, $stateParams){
var sessionID = $stateParams.sessionid;
return {
getJSONData: function(){
if(sessionID == 1){
return $http.get('json/session1_activities.json', {cache:false});
}
if(sessionID == 2){
return $http.get('json/session2_activities.json', {cache:false});
}
}
}
}])
This all works when I first load the page and go to the URL (for example) /session/1/activity/1 for the first time. But then when I load the URL (for example) /session/2/activity/2 the data is from session 1. When I debug in chrome, the factory doesn't get called the second time.
Am I not getting something conceptually, not using the correct methods, or are there any errors in my code?
The way you're passing in sessionID isn't really a good idea, why don't you pass it to the method in your factory itself?
return {
getJSONData: function(sessionID){
if(sessionID == 1){
return $http.get('json/session1_activities.json', {cache:false});
}
if(sessionID == 2){
return $http.get('json/session2_activities.json', {cache:false});
}
}
Controller:
localJSONData.getJSONData($stateParams.id)
.success(function(data){
$scope.activityData = data[activityID - 1];
});
The reason this works the first time your app loads is because $stateParams correctly evaluates the initial state's parameter, but doesn't update after that. The best way to do it would be what I posted above.
Related
I generate a code with editor.swagger and I want to code a GUI with angular for that code. Since I'm newbie in angular, I dind't understand well how to start programming. I first decide to create 3 files : index.html, index.js and service.js.
Here is a part of my code :
I don't know if it's the good beginning or not. But the problem is that I don't have any idea how what I should do for POST and DELETE. Can you help me please?
You can do the standard 4 methods in Angluar JS(POST,GET,PUT,DELETE). To use these in angular you have to use the $http service that angular provides. To find out more about it check their documentation: https://docs.angularjs.org/api/ng/service/$http
From the Angular $http documentation:
Complete list of shortcut methods:
$http.get
$http.head
$http.post
$http.put
$http.delete
$http.jsonp
$http.patch
You can also use the method parameter in the $http service. So $http(method: 'DELETE', ...)
var app = angular.module('app');
app.service('apiService', ['$http', function($http){
this.get = function(){
return $http.get(URL);
};
this.delete = function(id){
return $http.delete(URL, id);
}
this.post = function(data){
return $http.post(URL, data);
}
}]);
app.controller('controller', ['$scope', 'apiService', function($scope, apiService){
var getData = apiService.get().success(function(){
});
}]);
You can use $resource and return it as a service.
app.factory('factoryResource', ['$resource', function($resource) {
var resource = {
getResource: function(context) {
var rsc = $resource(context, {}, {'update': {method: 'PUT'}});
return rsc;
}
};
return resource; }])
In your controller you should inject the newly created service as below:
app.controller('myCtrl', function($scope, factoryResource) {
$scope.resource = factoryResource.getResource('http://localhost:8080/api/v1/projects');
$scope.resource.save(object, successCallback, errorCallback); //post
$scope.resource.query(successCallback, errorCallback); //get all
$scope.resource.get({id: object.id}, successCallback, errorCallback); //get a specific object
$scope.resource.delete({id: object.id}, successCallback, errorCallback); //delete
}
Hope this helps;
Basically we have 4 method for a REST operation
Create (POST)-- To Create a new User (just for an example, it can be anything)
Read (GET) -- To get all users
Update (PUT) -- To update a user's property
Delete (DELETE) -- To delete a user
Let me know if you need further clarification.
In angular using service you can do that.
var app = angular.module('app', []);
app.factory('UserService', function($http){
var user = {};
user.post = function(data){
return $http.post('url', data);
}
user.get = function(){
return $http.get('url');
}
user.delete = function(id){
return $http.delete('url');
}
user.update = function(id, data){
return $http.put('url', data);
}
return user
});
app.controller('Controller', function('UserService'){
// Get
UserService.get().success(function(){
});
UserService.post(data).success(function(){
});
UserService.delete(id).success(function(){
});
UserService.get(id, data).success(function(){
});
})
This can be done easily through $resource, if you URL is proper rest.
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've recently learned that ngResource request can be aborted either by specifying a timeout in ms or passing a deferred object.
The second solution does not seem to work for me, and I have no idea what I'm doing wrong. I've created a fiddle to demonstrate the problem http://jsfiddle.net/HB7LU/10977/
var myApp = angular.module('myApp',['ngResource']);
myApp.factory('myResource', function($resource) {
return {
getResource: function (aborter) {
var resource = $resource(
'http://api.openweathermap.org/data/2.5/weather?q=London,uk', {}, {
query: {
isArray: false,
timeout: aborter.promise
}
});
return resource;
}
};
});
myApp.controller('MyCtrl', function($scope, $q, $log, $timeout, myResource) {
var aborter = $q.defer();
setTimeout(function() {
$log.info('Aborting...');
aborter.resolve();
}, 10);
myResource.getResource(aborter).query().$promise.then(function(data) {
$scope.data = data;
});
});
I want to avoid sending multiple request at the time (I want to cancel the previous by calling aborter.resolve().
I was following this solution Angular $http : setting a promise on the 'timeout' config
Could you please advice me why it does not work?
It looks like it's an open issue with Angular 1.3: github.com/angular/angular.js/issues/9332 You're jsfiddle works if you drop back to 1.2.28.
Try using $timeout, instead of setTimeout, since that will take care of making sure your resolve is captured by angular $digest cycle.
myApp.controller('MyCtrl', function($scope, $q, $log, $timeout, myResource) {
var aborter = $q.defer();
$timeout(function() {
$log.info('Aborting...');
aborter.resolve();
}, 10);
myResource.getResource(aborter).query().$promise.then(function(data) {
$scope.data = data;
});
});
try to change this line of ngResource source code:
httpConfig[key] = copy(value);
in
httpConfig[key] = key !== 'timeout' ? copy(value) : value;
the problem is the copied promise
I am trying to get the http request result in my first controller. The http request is triggered by another controller. The problem I have is I am not sure how to detect if the request is done in my first controller. I have something like
First controller:
//I am not sure how to get the customer result if
//http requests are trigger by another controllers here.
customerFactory.getCustomerResult????
Second controller:
//trigger the http request..
var id = 1;
$scope.clickme = function() {
var obj = customerFactory.callApi(id)
}
My factory
customerFactory.callApi = function(id) {
return getCustomer(id)
.then(function(customer) {
return customer;
})
}
var getCustomer = function(id) {
return $http.get('/api/project1/getCustomer' + id);
}
return customerFactory;
html
<div ng-controller="firstCtrl">
//codes...
</div>
//other codes..
//other codes..
<div ng-controller="secondCtrl">
//codes...
</div>
The first and second controller are not related. They are far away from each other. How do I let firstCtrl detect the http request is done and get the customer data? Thanks a lot!
You can use a factory or a service which is a singleton to both be responsible for making the request and storing the data. The service and factory are both singletons and so the single instance persists for the execution of the application and the data and functions can be referenced from the controllers by injecting the factory or service (both are ways of defining providers with more concise syntax when configuration before use of the service/factory via a provider isn't needed).
angular.module("exampleApp", []).service('ExampleService', ["$http", "$q" ,function ($http, $q) {
var service = {
returnedData: [],
dataLoaded:{},
getData = function(forceRefresh)
{
var deferred = $q.defer();
if(!service.dataLoaded.genericData || forceRefresh)
{
$http.get("php/getSomeData.php").success(function(data){
angular.copy(data, service.returnedData)
service.dataLoaded.genericData = true;
deferred.resolve(service.returnedData);
});
}
else
{
deferred.resolve(service.returnedData);
}
return deferred.promise;
},
addSomeData:function(someDataToAdd)
{
$http.post("php/addSomeData.php", someDataToAdd).success(function(data){
service.getData(true);
});
}
};
return service;
}]).controller("ExampleCtrl", ["$scope", "ExampleService", function($scope, ExampleService){
$scope.ExampleService = ExampleService;
}]).controller("ExampleCtrl2", ["$scope", "ExampleService", function($scope, ExampleService){
ExampleService.getData();
$scope.ExampleService = ExampleService;
}]);