I'm using a service in order to pass data between different instances of an AngularJS controller. I know that this is not the best way to do it but it's the way that fits my case. The problem is that I cannot get data out of that Service.
var app = angular.module('MovieApp', ['ngResource']);
app.factory('factMovies', function($resource) { //this returns some movies from MongoDB
return $resource('/movies');
});
app.service('SnapshotService', function(factMovies) {
//this is used to pass data to different instances of the same controller
//omitted getters/setters
this.snapshots = [];
this.init = function() {
var ctrl = this;
var resp = factMovies.query({}, function() {
if (resp.error) {
console.log(resp.error)
} else {
tempDataset = []
//do stuff and put the results in tempDataset
ctrl.snapshots.push(tempDataset);
console.log(tempDataset); //prints fine
return tempDataset;
}
});
};
});
app.controller('TileController', function(SnapshotService) {
this.dataset = [];
this.filters = [];
this.init = function() {
var ctrl = this;
var data = SnapshotService.init(function() {
console.log(ctrl.data); //doesn't even get to the callback function
});
};
});
I really can't figure out what I'm doing wrong..
SnapshotService.init() doesn't take any parameters - meaning the anonymous function you pass in with the SnapshotService.init() call in TileController does nothing.
What you need to do is add the parameter to the init function definition and then call it in the code:
app.service('SnapshotService', function(factMovies) {
//this is used to pass data to different instances of the same controller
//omitted getters/setters
this.snapshots = [];
this.init = function(cb) {
var ctrl = this;
var resp = factMovies.query({}, function() {
if (resp.error) {
console.log(resp.error)
} else {
tempDataset = []
//do stuff and put the results in tempDataset
ctrl.snapshots.push(tempDataset);
console.log(tempDataset); //prints fine
cb(ctrl.snapshots);
}
});
};
});
Related
I'm trying to update a global angularjs module.value in one controller with an array, and then retrieving that global array through in a service. But the array doesn't exist.
app.js
app.factory('featureClaims', function($q) {
var featureClaims = {};
featureClaims.init = function() {
featureClaims.claims = [];
}
featureClaims.get = function() {
return $q.when(featureClaims.claims);
}
featureClaims.set = function(data) {
featureClaims.claims = data;
return $q.when(featureClaims.claims); // I'm using the $q library to return a promise.
}
return featureClaims;
});
loginController
let loginController = function($scope, loginService, toastrObj, featureClaims) {
$scope.login = function(){
featureClaims.init();
featureClaims.set(result.data.FeatureClaims); // updating ok here
}
}
app.controller("loginController", ["$scope", 'loginService', 'toastrObj', 'featureClaims',loginController]);
home service
let homeService= function(featureClaims) { // featureClaims.claims is null
return{
validateUser: function(expectedClaim) {
if(expectedClaim !== ""){
featureClaims.get().then(function(data){
return data.includes(expectedClaim); // data is return as undefined
})
}
return false;
}
}
};
app.factory('homeService',['featureClaims', homeService]);
I don't think you can use a value service this way. From this post the author states: "Note: Make sure that you never overwrite the value service/object as a whole otherwise your assignment is lost. Always reassign the property values of the value object. The following assignment is wrong and does not lead to the expected behavior"
Instead why don't you convert your value to a factory like so:
app.factory('featureClaims', function($q) {
var featureClaims = {};
featureClaims.init = function() {
featureClaims.claims = [];
}
featureClaims.get = function() {
return $q.when(featureClaims.claims);
}
featureClaims.set = function(data) {
featureClaims.claims = data;
return $q.when(featureClaims.claims); // I'm using the $q library to return a promise.
}
return featureClaims;
});
In your controller:
featureClaims.init();
// you need to wait for the promise to resolve with 'then'
featureClaims.set(['foo', 'bar']).then(function(response) {
console.log(response); // logs ["foo", "bar"]
});
featureClaims.get().then(function(response) {
console.log(response); // logs ["foo", "bar"]
});
Tested and working. You will want to create a get method that simply returns the data instead of setting it first.
I want to swap an array and get a json file, but don't know why nor where there's something wrong in my code (the service/controller part without an http request works though).
incriminated code
(function() {
(function() {
var JsonsService;
JsonsService = function($http) {
var pizze;
pizze = [];
return {
getPizze: function() {
$http.get('data/pizze-it.json').then(function(pizze) {
pizze = pizze.data;
});
}
};
};
JsonsService.$inject = ['$http'];
angular.module('myApp').factory('JsonsService', JsonsService);
})();
}).call(this);
(function() {
(function() {
var JsonsCtrl;
JsonsCtrl = function(JsonsService) {
var self;
self = this;
self.list = function() {
return JsonsService.getPizze();
};
};
JsonsCtrl.$inject = ['JsonsService'];
angular.module('myApp').controller('JsonsCtrl', JsonsCtrl);
})();
}).call(this);
Plnkr
I removed from app.js the entire block of code that is causing this error (service and controller), and placed it inside DontLoadThis.js (there's some markup to put back into main.html too)
This isn't necessarily the definite answer but there's a few things I've noticed that appear wrong.
Starting with your JsonsService:
JsonsService = function($http) {
var pizze;
pizze = [];
return {
getPizze: function() {
$http.get('data/pizze-it.json').then(function(pizze) {
pizze = pizze.data;
});
}
};
};
You're initialising a variable pizze but also using the callback variable pizze in the $http.get(). Instead I suggest:
var pizze = [];
...
$http.get('data/pizze-it.json').then(function(json_response) {
pizze = json_response.data;
});
This however is made redundant by the second issue: JsonsService.getPizze() doesn't actually return anything. A possible way around this would be to return the promise from getPizze() and deal with the result in the controller.
// in service
return {
getPizze: function() {
return $http.get('data/pizze-it.json');
}
};
// in controller
JsonsCtrl = function(JsonsService) {
var self;
self = this;
self.list = [];
JsonsService.getPizze().then(function (json_response) {
self.list = json_response.data;
});
};
Simply put, i have a Poller that returns msgdata and newdata variables based on conditions however the returned value in this case is always undefined. The Conditions should be overriding the initial variable initialising correct inside the service?
How can i get the Poller.msgdata and Poller.newdata to Return the TRUE or FALSE to the controller?
Controller:
app.controller('sidemenuController', ['$scope', 'projectsModal', 'sendMessageModal', 'Poller', '$timeout',
function($scope, projectsModal, sendMessageModal, Poller, $timeout) {
var update = function() {
$timeout(update, 5000);
$scope.inbox = Poller.msgdata;
$scope.project = Poller.newdata;
console.log("Updated SideMenu Controller: " + Poller.msgdata);
}
update();
$scope.projects = Poller.projects;
$scope.messages = Poller.messages;
$scope.sendMessage = sendMessageModal.activate;
$scope.showModal = function() {
projectsModal.deactivate();
projectsModal.activate();
};
$scope.toggle = function(){
$scope.checked = !$scope.checked
projectsModal.deactivate();
sendMessageModal.deactivate();
}
}]);
Service:
app.factory('Poller', Poller);
Poller.$inject = ['$http', '$timeout'];
function Poller($http, $timeout) {
var projectcache = { response: [], calls: 0 };
var msgcache = { response: [], calls: 0 };
var newdata;
var msgdata;
var poller = function () {
$timeout(poller, 5000);
$http.get('http://localhost/app/controllers/php/getProjects.php')
.then(function(r) {
if (r.data.projects.length > projectcache.response.length) {
newdata = true;
angular.copy(r.data.projects, projectcache.response);
} else {
newdata = false;
};
console.log(msgdata);
});
$http.get('http://localhost/app/controllers/php/getMessages.php')
.then(function(m) {
if (m.data.messages.length > msgcache.response.length) {
msgdata = true;
angular.copy(m.data.messages, msgcache.response);
} else {
msgdata = false;
};
});
};
poller();
return {
projects: projectcache.response,
messages: msgcache.response,
newdata: newdata,
msgdata: msgdata
};
};
Your polling method reassigns the local variables newdata and msgdata, but it doesn't reassign the fields of the object returned by the service, which are initialized to undefined and never modified after.
You need to keep a reference to the returned object in a variable:
var service = { ... };
...
return service;
and in the polling method, change the values inside the service:
service.newdata = false;
When you do
return {
projects: projectcache.response,
messages: msgcache.response,
newdata: newdata,
msgdata: msgdata
};
The data you get from Poller.newdata should always be the initial value of var newdata, because javascript do not pass by reference.
projects and messages work because you are doing angular.copy, which keeps the same reference.
An easy way to fix this would be passing back an object instead of boolean itself
var checkNew = {};
in poller function
checkNew.newdata = true;
in return
checkNew: checkNew
in controller
$scope.inbox = Poller.checkNew.msgdata;
$scope.project = Poller.checkNew.newdata;
A cleaner way (imo) to do this would be exposing the poller function as a service function to the controller. By this way you don't need to have a timeout on the service, it gets data whenever the controller calls it.
I'm trying to make a service that will load persons from the server on demand. The first version looked like this:
services.factory('PersonServiceOld', function(Restangular, ErrorService) {
var persons = [];
var requesting = [];
var get = function(id) {
if (requesting[id]) {
return persons[id];
}
requesting[id] = true;
persons[id] = {'id' : id, 'photoName' : '0.png'};
Restangular.one('persons', id).get().then(function(success) {
persons[id].firstName = success.firstName;
persons[id].lastName = success.lastName;
persons[id].photoName = success.photoName;
}, function(failure) {
requesting[id] = false;
ErrorService.serverError(failure);
});
return persons[id];
};
var reset = function() {
persons = [];
requesting = [];
};
return {
getPerson : get,
clearCache : reset,
};
});
That way I get a reference to an object right away and it will be filled with data slightly after. It worked well... until I noticed that in another use case, I also want to request the address of a person like
var person = PersonService.get(id);
person.one(address).get().then(.......
but the objects returned from my PersonService aren't Restangular objects. So I tried something else:
services.factory('PersonService', function(Restangular, ErrorService) {
var persons = [];
var get = function(id) {
if (!persons[id]) {
persons[id] = Restangular.one('persons', id);
persons[id].get().then(function(success) {
}, function(failure) {
ErrorService.serverError(failure);
persons[id] = null;
});
}
return persons[id]; // also tried: persons[id].$object
};
return {
getPerson : get
};
});
I hope somebody understands what I'm trying to do here and can give me a good pointer on how to achieve this.
Check this Plunkr for a complete example.
As Restangular returns promises, and your get function may be asynchronous or synchronous (in case you use your own cache), you need to create a promise for returning always the same type of object.
You can do it as described in the Angular documentation for $q service.
So your get function may look like :
var get = function (id) {
var deferred = $q.defer();
if (store[id]) {
deferred.resolve(store[id]);
} else {
Restangular.one('person', id).get().then(function (res) {
store[res.id] = res;
deferred.resolve(res);
}, function (err) {
deferred.reject(err);
});
}
return deferred.promise;
}
Then in your controller, for retrieving your data :
PersonService.get(475).then(function (person) {
// stuff
}, function (err) {
// err handling
});
I'm using the services directive in Angularjs not factory and I need to populate a json file to local variable;
/* Contains projects on the town */
leMaireServicess.service('cityService', function($http) {
// JSON regions and cities loader
this.cities = [];
// initCities
this.initCities = function() {
this.cities = $http.get('data/census/cities.js').success(function(data) {
return data;
});
return this.cities;
};
// Get city info
this.getCity = function() {
return this.cities;
};
});
And in my controller I have
// Saved game controller
leMaireControllers.controller('GameCoreCtrl', function($scope, cityService) {
/* Control the town project slides */
cityService.initCities();
$scope.city = cityService.getCity();
console.log($scope.city);
});
But instead of returning the actual data, it returns;
Object {then: function, catch: function, finally: function, success: function, error: function}
You can use a watch to make this work (see plunker)
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope,cityService) {
//$scope.cities = [];
$scope.service = cityService;
cityService.initCities();
$scope.$watch('service.getCity()', function(newVal) {
$scope.cities = newVal;
console.log(newVal)
});
});
app.service('cityService', function($http) {
var that = this;
this.cities = [];
this.initCities = function() {
$http.get('data.js').success(function(data) {
that.cities = data.cities;
});
};
this.getCity = function() {
return this.cities;
};
});
$http returns a promise which is what you're setting this.cities to.
This might help explain more,
https://stackoverflow.com/a/12513509/89702
In your controller you should be able to do something like this...
cityService.initCity().then(function(data) { $scope.city = data; }
You are working with promises which represent the result of an action that is performed asynchronously. Try it this way:
leMaireServicess.service('cityService', function($http) {
this.promise = {};
// initCities
this.initCities = function() {
this.promise = $http.get('data/census/cities.js');
};
// Get city info
this.getCity = function() {
return this.promise;
};
});
And in the controller you need to put your code in a callback:
// Saved game controller
leMaireControllers.controller('GameCoreCtrl', function($scope, cityService) {
/* Control the town project slides */
cityService.initCities();
cityService.getCity().then(function(result){
$scope.city = result.data;
console.log($scope.city);
});
});