I have a factory House
'use strict';
myApp
.factory('House', [ '$http', '$location', '$rootScope', function($http, $location, $rootScope){
var numberOfDoors;
return {
loadHouse: function(){
numberOfDoors = 1;
},
numberOfDoors: numberOfDoors
};
}]);
And I have a controller Owner
myApp
.controller('OwnerCtrl', ['$rootScope', '$scope', '$location', 'House', function($rootScope, $scope, $location, House) {
$scope.buildMe = function() {
//use value from house
var sayHelloToDoors = House.numberOfDoors;
};
}]);
If I run a function House.loadHouse() in some other controller in order to set the variable numberOfDoors - I do set it, but when I switch to a page to reuse that number, I get a undefined message in Owner controller.
Why the value is cleared? It seems like another instance of House is transfered.
Could anybody help?
This is because you're assigning the value of private numberOfDoors to the field numberOfDoors in the factory.
// This following snippet ...
myApp.factory('house', function() {
var numberOfDoors;
return {
numberOfDoors: numberOfDoors
};
});
// ... will actually become
myApp.factory('house', function() {
var numberOfDoors; // === undefined
return {
numberOfDoors: undefined
};
});
Even if you would assign the private numberOfDoors an initial value, it would not behave the way you want it to.
myApp.factory('house', function() {
var numberOfDoors = 123;
return {
loadHouse: function() {
numberOfDoors = 1; // will change the private variable
// not the exposed object variable
},
numberOfDoors: numberOfDoors // will always be 123
};
});
Easiest way to make this work is doing something like this:
myApp.factory('house', function() {
return {
reset: function() {
this.numberOfDoors = 0;
},
numberOfDoors: 0
};
});
You can play with in action at this plunker.
Edit:
To encapsulate the number of doors you could do something like this:
myApp.factory('house', function() {
var _numberOfDoors = 0;
return {
reset: function() {
_numberOfDoors = 0;
},
numberOfDoors: function(value) {
if(value!==undefined) {
_numberOfDoors = value;
}
return _numberOfDoors;
}
};
});
Now from your controller you can:
var count = house.numberOfDoors(); // Get the numberOfDoors
house.numberOfDoors(++count); // Set the numberOfDoors
You'll have to change "numberOfDoors: numberOfDoors" to "numberOfDoors: function(){return numberOfDoors;}"
Please see this simple: (available in plnkr)
var service = (function(){
var privateVar = 0;
return{
updateVar: function(val){
privateVar = val;
},
getVar2: privateVar,
getVar: function(){
return privateVar;
}
}
})();
var instanceA = (function(){
service.updateVar(1);
alert(service.getVar());
})();
var instanceB = (function(){
alert(service.getVar());
alert(service.getVar2);
})();
Related
/*service */
app.service('sharedProperties', function () {
var property = 'First';
return {
getProperty: function () {
return property;
},
setProperty: function(value) {
property = value;
}
};
});
/*first contoller */
app.controller('loginCtrl',function($scope,$location,$http,$window,sharedProperties){
$scope.submit =function(){
var username=$scope.username;
var pass=$scope.password;
sharedProperties.setProperty(username);
$location.path('/userdashboard');
$window.location.reload();
});
}
});
/*second controller*/
app.controller('empController', function($route,$scope,$http,$routeParams,sharedProperties){
$scope.getEmployees = function(){
alert( sharedProperties.getProperty());
};
};
Try this, it will work for you. :
<div ng-app="myApp" ng-controller="myCtrl">
<button ng-click="sendData();"></button>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
function sendData($scope) {
var arrayData = [1,2,3];
$scope.$emit('someEvent', arrayData);
}
});
app.controller('yourCtrl', function($scope, $http) {
$scope.$on('someEvent', function(event, data) {
console.log(data);
});
});
</script>
Service does not need to return anything. You have to assign everything in this variable. Because service will create instance by default and use that as a base object.
app.service('sharedProperties', function () {
this.property = 'First';
});
Then in controller
sharedProperties.property = $scope.username;
Had you been looking to use factory
app.factory('sharedProperties', function () {
var factory = {};
factory.property = 'Hello';
factory.setProperty = function (value) {
factory.property = value;
};
return factory;
});
Then in controller you would use it
sharedProperties.setProperty($scope.username); // Setter
$scope.var = sharedProperties.property; //getter
EDIT
Working Plnkr
You can assign members to $rootScope, which will store data globally for your app. Just inject $rootScope to each controller.
For instance...
/*first controller */
app.controller('loginCtrl',function($scope,$rootScope,$location,$http,$window,sharedProperties){
$scope.submit =function(){
var username=$scope.username;
var pass=$scope.password;
$rootScope.username = username;
$location.path('/userdashboard');
$window.location.reload();
});
}
});
This will make 'username' available to any controller that injects and consumes $rootScope.
/*second controller*/
app.controller('empController', function($route,$scope,$rootScope,$http,$routeParams,sharedProperties){
$scope.getEmployees = function(){
alert($rootScope.username);
};
};
I'm very new to AngularJS, how can I pass input scope from first controller to the second controller for the data $scope.requestURL
I've search about the service method but I have no idea how to apply it.
.controller('ZipController', ['$scope', function($scope) {
$scope.zipCode = '10028';
$scope.setURL = function() {
$scope.requestURL = 'http://congress.api.sunlightfoundation.com/legislators/locate?zip=' + $scope.zipCode + '&apikey=xxxxx';
};
}])
.controller('ListController', ['$scope', '$http',
function($scope, $http) {
$http.get($scope.requestURL).success(function(data) {
console.log(data.results);
$scope.congress = data.results;
});
}]);
Here is a quick solution: ..you don't have to use the $http core service for your case:
You can also read more about angular's constant service..
(function(angular) {
var app = angular.module('myServiceModule', []);
app.controller('ZipController', function($scope, myService) {
$scope.zipCode = '10028';
myService.setFunc($scope.zipCode);
myService.zipCode = $scope.zipCode;
});
app.controller('ListController', function($scope, myService) {
$scope.requestURL = myService.getFunc();
});
app.factory('myService', function() {
var zipCode;
var setFunc = function(zip) {
zipCode = zip;
};
var getFunc = function() {
return 'http://congress.api.sunlightfoundation.com/legislators/locate?zip=' + zipCode + '&apikey=xxxxx'
};
return {
zipCode: zipCode,
setFunc: setFunc,
getFunc: getFunc
};
});
})(window.angular);
Try setting it to $rootScope.requestURL and access it from the second controller.
i have 2 controllers who are not in the same scope or have a parent child relation.
So i want to call from controlleB a function in ControllerA. In my case its a listContoller with an addItem function and i want to call this function from a addItemController somewhere else on the page after clicking submit. i know this should work with a service, but i dont know how.
app.controller("listCtrl", ["$scope", "listSvc", function ($scope, listSvc){
$scope.list.data = listSvc.load("category");
$scope.addItem = function(newitem) {
$scope.list.data.unshift(newitem);
...
}
}]);
app.controller("addItemCrtl", ["$scope", "listSvc", function ($scope, listSvc){
$scope.addItem = function() {
listSvc.addItem($scope.newItem);
}
}]);
app.service('listSvc', function() {
return{
load: function(section){
...
},
addItem: function(item){
addItem(item); <<-- call function in listController
}
}
});
UPDATE
k is this better? i put the list.data inside my service and i watch from my controller if the list change and put it on the scope from my controller that ng-repeat can do his work... is this appraoch better? or have someone better tips for me how i should do this...
app.service('listSvc', ['$http', function($http) {
var list = {};
return {
list:{
get: function () {
return list.data;
},
set: function (data) {
list.data = data;
}
},
addItem: function(item){
var response = $http.post("/api/album/"+$scope.list.section, item);
response.success(function(){
list.data.unshift(item);
console.log("yeah success added item");
}).error(function(){
console.log("buuuh something went wrong");
});
return response;
},
load: function(section){
var response = $http.get("/api/album/"+section);
response.success(function(data){
list.set(data);
list.section = section;
console.log("yeah success loaded list");
}).error(function(){
console.log("buuuh something went wrong");
});
return response;
}
};
}]);
and in my controllers i do this
app.controller("listCrtl", ["$scope", "listSvc", function ($scope, listSvc){
listSvc.load("category");
...
$scope.$watch('listSvc.list.get()', function(data) {
$scope.list.data = data;
});
...
}]);
app.controller("addItemCrtl", ["$scope", "listSvc", function ($scope, listSvc){
...
$scope.addItem = function() {
listSvc.addItem($scope.newItem);
}
...
}]);
gregor ;)
I just solved this myself! Perhaps this may help:
The function inside of my Controller:
var timeoutMsg = function() {
vm.$parent.notification = false;
};
The function inside my Service (I had to pass in $timeout as well as the name of the function from my Controller, now it works):
// original broken code:
// this.modalSend = function(vm) {
// fixed:
this.modalSend = function(vm, $timeout, timeoutMsg) {
vm.$parent.sendTransaction = function() {
// Show notification
vm.$parent.message = 'Transaction sent!';
vm.$parent.notification = true;
$timeout(timeoutMsg, 4000);
// original broken code:
// $timeout(timeoutMsg(), 4000);
};
}
var vm = $scope
Is it legal for a controller to do something like this in Angular?
$rootScope.someArbitaryObject = ["fee", "fie", "fo", "fum];
or
$rootScope.foo = {name: "Jane Q. Public", favoriteColor: "green"}
Yes, it is legal but only if you want ALL controllers to have access to that model.
A better practice is to use services that you can then inject to one or more controllers:
var myApp = angular.module('myApp', []);
myApp.factory('MyService', function () {
return { message: "I'm data from a service" };
});
myApp.controller('FirstCtrl', function($scope, MyService) {
$scope.data = MyService;
});
myApp.controller('SecondCtrl', function($scope, MyService) {
$scope.data = MyService;
});
Any change you make to MyService properties in one controller will affect all the other controllers that use MyService.
regarding the question in your comments, a good way to share date is through localstorage (or sessionStorage). I wrote a storageService which allows you to save, load and delete.
angular.module(yourApplication).service('storageService', [
function() {
// implementation using localStorage. Future possibility to user $cookie service here, or sessionStorage, depends on what you want
return {
save: function(key, jsonData, expirationMin){ // default is 30 minute expiration
if(!expirationMin)
expirationMin = 30;
var expirationMS = expirationMin * 60 * 1000;
var record = {
value: JSON.stringify(jsonData),
timestamp: new Date().getTime() + expirationMS
};
localStorage.setItem(key, JSON.stringify(record));
return jsonData;
},
load: function(key){
var record = JSON.parse(localStorage.getItem(key));
if (!record){
return false;
}
return (new Date().getTime() < record.timestamp && JSON.parse(record.value));
},
remove: function(key){
localStorage.removeItem(key);
}
};
}
]);
Another way using services (Modified Yoni's code a little):
var myApp = angular.module('myApp', []);
myApp.service('MyService', function () {
var someData = 'test';
return {
getData: function(){ return someData},
setData: function(input){ someData = input;}
};
});
myApp.controller('FirstCtrl', function($scope, MyService) {
$scope.data = MyService.getData();
});
myApp.controller('SecondCtrl', function($scope, MyService) {
$scope.data = MyService.getData;
});
I am trying to share an id between controllers in angular
I have created a service as follows:
app.factory("idService", function() {
var id;
addId = function(id) {
id = id;
};
getId = function() {
return id;
};
});
In my controller I am trying to use this service as follows:
app.controller('photoFormController', ['$scope', '$http', 'idService' , function($scope, $http, idService) {
$scope.id = idService.getId();
}]);
I am getting an error of can't call method of undefined, obviously I am injecting the service incorrectly. Can someone help ?
EDIT:
Based on the solution below, the service no longer generates errors, however I am unable to get the id varaible back, I can see that it gets set from one controller, however it remains undefined in when retrieving :
app.factory("idService", function() {
var id;
addId = function(id) {
id = id;
console.log("added id of: " + id);
};
getId = function() {
console.log("trying to return : " + id);
return id;
};
return {
addId: addId,
getId: getId
};
});
You need to return an object inside factory. This returned object is your service instance:
app.factory("idService", function() {
var _id; //use _id instead to avoid shadowing your variable with the same name id
var addId = function(id) { //use var to avoid creating a property on the global object
_id = id;
};
var getId = function() { //use var to avoid creating a property on the global object
return _id;
};
return {
addId : addId ,
getId : getId
};
});
This is because you need to place the id within an object.
fiddle
This idea is as follows:
myApp.controller('ctrl1', function($scope, myservice) {
$scope.updateId = function() {
myservice.setId($scope.input)
};
});
myApp.controller('ctrl2', function($scope, myservice) {
$scope.data = myservice.getData();
});
myApp.service('myservice', function() {
var myservice = this;
var data = {};
myservice.setId = function(newValue) {
data.id = newValue;
};
myservice.getData = function() {
return data;
}
});
This way the data object that you get from your service sort of static, and the mutable member that you are outputting is contained within it.
You don't need to create a service in order to share some variable, just use value():
JavaScript
angular.module('app',[]).
value('share', {id: 123}).
run(['share', function(share) {
console.log(share.id); // <= 123
share.id = 345;
}]).
controller('appController', ['$scope', 'share', function($scope, share) {
$scope.id = share.id; // <= 345
}]);
Plunker: http://plnkr.co/edit/m55hmFgBvi1rwVsYMeKU?p=preview
Example of service which store data between controllers:
'use strict';
angular
.module('app')
.factory('youService', youService);
youService.$inject = ['$rootScope'];
function youService($rootScope) {
var service = {};
var questions = [];
// Data
function getData() {
return questions;
};
function setData(newQuestion) {
questions.push(newQuestion);
};
function resetData() {
questions = {};
};
// Services
service.getData = getData;
service.setData = setData;
service.resetData = resetData;
return service;
};
In controller:
angular.module('app')
.controller('yourController', yourController);
stepFourController.$inject = ['$scope', 'youService'];
function yourController($scope, youService){
// Get saved data from service
$scope.model = youService.getData();
// Set data to service
youService.setData($scope.model);
// Reset data in service
youService.resetData();
};
Best way to share data between controller is through services or factories
The service can be written as:
var myApp = angular.module('myApp', []);
myApp.service('shareId', [function () {
var shareIdService = this;
shareIdService.id = '';
shareIdService.setId = function (id) {
shareIdService.id = id;
}
shareIdService.getId = function () {
return shareIdService.id;
}
}]);
or factory may be written like as
myApp.factory('shareId', [function () {
var id = '';
return {
setId:function (id){
id=id;
},
getId:function (){
return id;
}
}
}])