Is angularJS service singleton? - angularjs

I have a service method and it will change the value of a boolean variable (false is default value) and return back to controller.
Am calling this service method by clicking on a button.
Consider, am clicking this button and now the variable value is true.
now, am accessing this same service method from another one controller and it is false.. why?
Whats wrong?
first controller,
.controller('myController1',....
$scope.value = false;
$scope.buttonClick = function(){
$scope.value = myService.setValue(value);
}
second controller,
.controller('myController2',.....
$scope.value = myService.getValue();
service,
angular.module('myModule', [])
.service('myService', ['OtherTypes',
function (OtherTypes) {
var myServiceVariable = false;
return {
setValue: function (value) {
myServiceVariable = !value;
return (myServiceVariable);
},
getValue: function () {
return myServiceVariable;
}
}
}
]);

Looks like you have a typo: you're separating the two functions with a , and not a ;. Change to:
myServiceVariable = false;
setValue: function (value) {
myServiceVariable = !value;
return (myServiceVariable);
};
getValue: function () {
return myServiceVariable;
};
}
Also, since you're getting the value in the 2nd controller as a return value from a function and not a direct reference to the service variable itself, don't expect it to update automatically. You'll have to call the getValue() function everytime.

hi the following code should show that services are singleton in angularjs.
myApp = angular.module("myApp",[]);
myApp.service("myService", function(){
myServiceVariable = false;
return {
setValue: function (value) {
myServiceVariable = value;
return (myServiceVariable);
},
getValue: function () {
return myServiceVariable;
}
}
});
myApp.controller("controller1", function($scope, myService){
console.log(myService);
$scope.clickHandler = function(){
myService.setValue(!myService.getValue());
}
});
myApp.controller("controller2", function($scope, myService){
console.log(myService);
$scope.getServiceValue = function(){
return myService.getValue();
}
});
For a working demo you can go here

Related

Angular variable in factory?

In a Angular app i have a couple of calls to a WebAPI service.
The first call, lets call it call1, should determine a true/false value of a variable.
So i have this
vm.call1.$promise.then(function (data) {
$rootScope.variable1 = data.variable;
});
This variable is to be used inside a factory i have;
myApp.factory('myStore', function ($http, $q, $rootScope) {
var showAll = $rootScope.variable1;
var get = function () {
if (showAll) {
//do this
} else {
//do this
}
};
return {
get: get
};
});
My problem is, that the factory above is loaded on pageload, and before the promise, and therefore the value is undefined.
How can i get the value, over to my factory, after the promise is complete?
No rootscope example: You can set the showAll flag manually:
vm.call1.$promise.then(function (data) {
myStore.setShowAll(data.variable);
});
and in the Factory:
myApp.factory('myStore', function ($http, $q) {
var showAll = 'true or false to be a default';
var get = function () {
if (showAll) {
//do this
} else {
//do this
}
};
var setShowAll = function(value) {
showAll = value;
};
return {
get: get,
setShowAll: setShowAll
};
});
Rootscope example: If you for some reason really need to use $rootScope for this you can just check for $rootScope value when you get, you don't have to store the value in a varibale.
myApp.factory('myStore', function ($http, $q, $rootScope) {
var get = function () {
if ($rootScope.variable1) {
//do this
} else {
//do this
}
};
return {
get: get
};
});

Best way to ng-hide my headMenu from different controller

I want to hide my headmenu.
app.controller("kpiOverviewCtrl", function ($scope, $stateParams,) {
"use strict";
var setUpController = function () {
$scope.headmenu = $state.current.controller === "kpiCompareCtrl";
};
$rootScope.$on('$locationChangeSuccess', function () {
setUpController();
});
$rootScope.$on('$stateChangeSuccess', function () {
setUpController();
});
setUpController();
});
As you can see on the code it sets headmenu to true on a controller switch. It works fine. But now I want to set headmenu to true on a ng-click statment from a controller thats already been loaded.
app.controller("kpiDetailsCtrl", function ($scope, $state) {
"use strict";
$scope.loadDataForMonthView = function () {
$scope.errorNoDataForDate = false;
$scope.yearMode = false;
$scope.monthMode = true;
//Here I want to set $scope.headmenu = true;
//Other code.....
};
Any nice suggestions?
Use a broadcast. They're a great way for communication between controllers.
Create a regular function in your main controller, which you can call from within the controller itself.
app.controller('Main', function($scope) {
function setHeadMenu() {
// Set menu to true
}
$scope.$on('setHeadMenu', function() {
setHeadmenu(); // Fires on broadcast
})
});
Create an ng-click which fires a broadcast from the other controller
app.controller('Second', function($scope) {
$scope.click = function() {
$scope.$broadcast('setHeadMenu'); // Send a broadcast to the first controller
}
});
You can declare new method to $rootScope inside kpiOverviewCtrl:
app.controller("kpiOverviewCtrl", function ($scope, $stateParams, $rootScope) {
"use strict";
//your code...........
$rootScope.setUpController = setUpController;
});
And then call it from kpiDetailsCtrl controller:
app.controller("kpiDetailsCtrl", function ($scope, $state, $rootScope) {
"use strict";
$scope.loadDataForMonthView = function () {
$scope.errorNoDataForDate = false;
$scope.yearMode = false;
$scope.monthMode = true;
$rootScope.setUpController();
}
});
First dummy suggestion:
$scope.loadDataForMonthView = function () {
$scope.headmenu = true; //(or false)
}
But most likely you are using some asynchrounous call, so something like this would be better:
$scope.loadDataForMonthView = function () {
// First: you need some promise object
// the most simple is to use $http
var promise = $http({url: 'some.url', method: 'GET'});
promise.then(function() {
// the data have arrived to client
// you can hide or show menu according to your needs
$scope.headmenu = true; //(or false)
})
}
More on how $http works is in the docs https://docs.angularjs.org/api/ng/service/$http

Returned Service Value always Undefined inside Controller?

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.

How do I invoke a factory constructor with angular.mocks.inject?

Consider this code:
beforeEach(inject(function (_User_) {
user = _User_;
}));
And this module/service:
angular.module('app.userModule', [])
.factory('User', function() {
function User(data) {
data.forEach(function (attr) {
if (data.hasOwnProperty(attr))
this[attr] = data[attr];
})
};
User.prototype.getSomeAttr() { return this.attr; }
return User;
};
How on earth can I pass 'data' into the User function constructor, using inject?
Edit: my example is derived from code here: http://sauceio.com/index.php/2014/07/angularjs-data-models-http-vs-resource-vs-restangular/

angularjs calling an inner function within service results in undefined

I am new to angular. I have a service where I call a function by another function within the service. But in my controller is shows as undefined. See below
//my Service
myApp.service("LocationService", function() {
var srv = {}
srv.msg = {long:0, lat:0};
srv.onSuccess = function() {
this.msg.lat = 32;
},
srv.onError = function() {
this.msg.long = 99;
},
srv.getGpsFix = function() {
this.onSuccess();//fails in controller
}
return srv;
});
//my Controller
myApp.controller("MusicCtrl", ["$scope", "LocationService", function($scope, LocationService) {
//undefined
console.log(locationService.getGpsFix());
}]);
It is correct that locationService.getGpsFix() would return undefined.
If you intended for it to return a value, then use the return keyword in your function.
srv.getGpsFix = function() {
this.onSuccess();
return 'It worked!!!';
};
locationService.getGpsFix() is undefined. In your controller, your service is available as LocationService. Hence, use LocationService.getGpsFix()

Resources