AngularJs: pass $scope variable with service - javascript

I have two controllers and in one of them I declared a $scope variable that I would like visible in the second controller.
First controller
app.controller('Ctrl1', function ($scope) {
$scope.variable1 = "One";
});
Second Controller
app.controller('Ctrl2', function ($scope, share) {
console.log("shared variable " + share.getVariable());
});
I researched the best Angular approach and I found that is the use of service. So I added a service for Ctrl1
Service
.service('share', function ($scope) {
return {
getVariable: function () {
return $scope.variable1;
}
};
});
This code return this error:
Unknown provider: $scopeProvider <- $scope <- share
So my question is: is possible share $scope variable between controllers? Is not the best Angular solution or i'm missing something?
Sorry for my trivial question but I'm an Angular beginner.
Thanks in advance
Regards

Yes, it is possible to share the scope variables between controllers through services and factory.But, the $scope variables are local to the controller itself and there is no way for the service to know about that particular variable.I prefer using factory, easy and smooth as butter. If you are using the service of factory in a separate file you need to include the file in index.html
app.controller('Ctrl1', function ($scope,myService,$state) {
$scope.variable1 = "One";
myService.set($scope.variable1);
$state.go('app.thepagewhereyouwanttoshare');//go to the page where you want to share that variable.
});
app.controller('Ctrl2', function ($scope, myService) {
console.log("shared variable " + myService.get());
});
.factory('myService', function() {
function set(data) {
products = data;
}
function get() {
return products;
}
return {
set: set,
get: get
}
})

You cannot inject $scope dependency in service factory function.
Basically shareable service should maintain shareable data in some object.
Service
.service('share', function () {
var self = this;
//private shared variable
var sharedVariables = { };
self.getSharedVariables = getSharedVariables;
self.setVariable = setVariable;
//function declarations
function getSharedVariables() {
return sharedVariables;
}
function setVariable() {
sharedVariables[paramName] = value;
}
});
Controller
app.controller('Ctrl1', function ($scope, share) {
$scope.variable1 = "One";
share.setVariable('variable1', $scope.variable1); //setting value in service variable
});
app.controller('Ctrl2', function ($scope, share) {
console.log("shared variable " + share.getSharedVariables());
});

Your try with service it quite good, but you shouldn't try to use $scope in dependency injection into the service code. Service is meant to be a data provider to you, then if you want to share some data between 2 controllers, you should make place for this data in your service
.service('share', function ($scope) {
this.variable1 = '';
return {
getVariable: function () {
return this.variable1;
}
setVariable(variable)
{
this.variable1 = variable;
}
};
});
app.controller('Ctrl1', function (share) {
$scope.variable1 = share.getVariable();
});
This is the broader description of this solution:
https://stackoverflow.com/a/21920241/4772988

Best way is really using services. Services have only access to $rootScope, they don't have their own $scope.
However, you shouldn't use scopes for this task. Just make a service with some shared variable outside any scopes.
.service('share', function ($scope) {
var variable = 42;
return {
getVariable: function () {
return variable;
}
};
});
app.controller('Ctrl', function ($scope, share) {
console.log("shared variable " + share.getVariable());
// Watch for changes in the service property
$scope.$watch(function() { return share.getVariable(); }, function(oldValue, newValue) {
// whatever
});
});

First, your service should be like this:
app.service('share', function () {
// this is a private variable
var variable1;
return {
// this function get/sets the value of the private variable variable1
variable1: function (newValue) {
if(newValue) variable1 = newValue;
return variable1;
}
};
});
To set the value of the shared variable pass the value to the function we created on the service
app.controller('Ctrl1', function ($scope, share) {
$scope.variable1 = "One";
// share the value of $scope.variable1
share.variable1($scope.variable1);
});
To get the value of the shared variable also use the function in the service without passing a value
app.controller('Ctrl2', function ($scope, share) {
console.log("shared variable " + share.variable1());
});

Update: Using $rootScope is considered bad practice.
What you need is the $rootScope. The $scope is just for one controller. Here is an example:
angular.module('myApp', [])
.run(function($rootScope) {
$rootScope.test = new Date();
})
.controller('myCtrl', function($scope, $rootScope) {
$scope.change = function() {
$scope.test = new Date();
};
$scope.getOrig = function() {
return $rootScope.test;
};
})
.controller('myCtrl2', function($scope, $rootScope) {
$scope.change = function() {
$scope.test = new Date();
};
$scope.changeRs = function() {
$rootScope.test = new Date();
};
$scope.getOrig = function() {
return $rootScope.test;
};
});

Related

How can I use Angular JS data inside JavaScript(Google Chart)?

I want to use my angular JS scope data inside my google chart or JavaScript
My angular JS file given below
angular.module('reports').controller('ReportInfoCtrl', ['$scope', 'reports', '$rootScope','$location','blockUI',
function ($scope, reports, $rootScope, $location, blockUI) {
$scope.getReportDetail = function () {
blockUI.start();
reports.getReportInformation().then(function (data) {
blockUI.stop();
if (data !== undefined) {
$scope.report_details = data;
}
});
};
}]);
Yes, sure. You can access your scope variable of controller out side your angular.
var controllerElement = document.querySelector('[ng-controller="ReportInfoCtrl"]'); // You can use javascript or Jquery to select the controller's div element.
var controllerScope = angular.element(controllerElement).scope(); // Angular provided the interface to access angular's scope
var asd = controllerScope.report_details; // Now you can access all scope variable using 'controllerScope'
Update
angular.module('reports').controller('ReportInfoCtrl', ['$scope', 'reports', '$rootScope','$location','blockUI',
function ($scope, reports, $rootScope, $location, blockUI) {
$scope.getReportDetail = function () {
blockUI.start();
reports.getReportInformation().then(function (data) {
blockUI.stop();
if (data !== undefined) {
$scope.report_details = data;
}
return data;
});
};
}]);
And in your js file,
var asd = controllerScope.getReportDetail();
Asynchronous scope manipulations must occur within a $scope.apply to be noticed by angular.

best practice to set controller scope variable from factory function?

I have working code below to set controller 'HelloCtrl' scope variable 'root' from factory 'testFactory' function setRoot(). I'm using ng-submit="testSubmit()" with ng-model="test" in my HTML. I'm afraid it's not the best practice, what else would you recommend ?
angular.module('testApp', [])
.controller('HelloCtrl', function ($scope, testFactory, testService) {
$scope.root='initial';
$scope.testSubmit = function () {
testFactory.setRoot($scope)
}
})
.factory('testFactory', function(){
return {
setRoot: function(scope){
scope.root=scope.test
}
}
})
The only way to do what you want is to return a value from a factory and then bind this value to the $scope:
angular.module('testApp', [])
.controller('HelloCtrl', function ($scope, testFactory, testService) {
$scope.root = 'initial';
$scope.testSubmit = function() {
$scope.root = testFactory.setRoot();
}
})
.factory('testFactory', function() {
return {
setRoot: function() {
return 'Some value';
}
}
});
Like I stated in the previous question you asked, $rootScope and $scope cannot be bound from a service or factory. The way you should utilize these are rather by returning a value from them which you then use in your controller. The controller is what should be binding things to the scope, not a service or factory.
In this example $scope.root will be updated with the value of what testFactory.setRoot() returns, which in this case is 'Some value'.
Here is another question which you can use to gain a better understanding:
Accessing $scope in AngularJS factory?

how to get/set variables outside of controller/module?

Let's say I have a predefined module/controller which sets the apple as green.
var _core = angular.module('_core', []);
_core.controller('mainController', function($scope, $controller, $http) {
$scope.apple = 'green';
});
Can I get the apple outside of the controller? Something like.
_core.mainController.apple
Is this possible? I also need to set variables with external plugins, sorry I'm a complete angular noob, its a bit daunting.
If you want the value to be accessible outside the controller, then you can store it in $rootScope instead of $scope and you can directly use the values stored in $rootScope where it is injectable. So the code becomes:
var _core = angular.module('_core', []);
_core.controller('mainController', function($scope, $controller, $http, $rootScope) {
$rootScope.apple = 'green';
});
Now in some other place say a factory, you can use it as:
var _core1 = angular.module('_core1', []);
_core1.factory('someFactory', function($scope, $rootScope, $http) {
var fruit = $rootScope.apple;
//variable fruit now contains green
});
You can use factory to get set any module outside the controller.
var App = angular.module('app', []);
App.factory('messages', function () {
var messages = {};
messages.list = [];
messages.add = function (someString) {
messages.list.push(someString);
};
messages.get = function() {
};
messages.clearList = function () {
messages.list.length = 0;
}
return messages;
});
And you can call this service method into your controller.
App.Controller('myController',['$scope', 'messages', function(scope, messages) {
messages.add('Hello');
var myListy = messages.get();
}]);

AngularJS: How to share scope functions and variables with other controllers

I've multiple controllers in my application, where I have some duplicate code like:
$scope.alert = null;
$scope.addAlert = function (message) {
$scope.alert = { type: 'danger', msg: message };
};
$scope.clearAlerts = function () {
$scope.alert = null;
};
What is the recommended way sharing these scope functions and variables in AngularJS? Using controller inheritance?
Create a one controller and then place common methods inside that controller scope. So that you can use that scope anywhere else and get access to method inside controller.
Controller
app.controller('commonCtrl', function($scope) {
$scope.alert = null;
$scope.addAlert = function(message) {
$scope.alert = {
type: 'danger',
msg: message
};
};
$scope.clearAlerts = function() {
$scope.alert = null;
};
});
Thereafter use scope of this controller by inject it using $controller, and then inside curly brace you could assign common controller scope to the current scope of controller.
Utilization of Common Controller
app.controller('testCtrl', function($scope, $controller) {
//inject comomon controller scope to current scope ,
//below line will add 'commonCtrl' scope to current scope
$controller('commonCtrl', { $scope: $scope });
//common controller scope will be available from here
});
Or more precise way would be using common sharable service, that exposed two method and alert data, you can use this service method by injecting service name inside your controller.
Service
app.service('commonService', function($scope) {
this.alert = null;
this.addAlert = function(message) {
this.alert = {
type: 'danger',
msg: message
};
};
this.clearAlerts = function() {
this.alert = null;
};
});
Utilization of service inside Controller
app.controller('testCtrl', function($scope, commonService) {
console.log(commonService.alert);
commonService.addAlert("Something");
console.log("Updated Alert" + commonService.alert);
});
Hope this has cleared your concept, Thanks.
My own solution for this use case was to define a type of Observer Pattern.
The code was structured in the following way:
var app = angular.module('testModule', []);
app.factory('alertService', ['$timeout', function($timeout){
var alertListeners = [];
this.register = function (listener) {
alertListeners.push(listener);
};
this.notifyAll = function (data) {
for (// each listener in array) {
var listenerObject = alertListeners[i];
try { // do not allow exceptions in individual listeners to corrupt other listener processing
listenerObject.notify(data);
} catch(e) {
console.log(e);
}
}
};
}]).
directive('myAlerts', ['alertService', function(alertService){
var alertDirectiveObserver = function($scope, alertService) {
this.notify = function(data) {
/*
* TO DO - use data to show alert
*/
};
/*
* Register this object as an event Listener. Possibly supply an event key, and listener id to enable more resuse
*/
alertService.register(this);
$scope.on('$destroy', function() {
alertService.unregister(// some listener id);
});
};
return {
restrict: 'A',
template: '<div ng-class="alertClass" ng-show="alertNeeded">{{alertMessage}}</div>',
controller: ['$scope', 'alertService', alertDirectiveObserver],
link: function(scope){
}
}
}]).
controller('alertShowingController', ['$scope', 'alertService', function($scope, alertService){
alertService.notifyAll({'warning', 'Warning alert!!!'})
]);
The alertShowingController is a simple example of how all controllers can simply inject the alertService and generate an event.
My own implementation is more elaborate in that it uses separate event keys to allow the controllers to generate other event notifications.
I could then define a single div that was in a fixed position at the top of the page that would dispay bootstrap alerts.
<div my-alerts ng-repeat="alert in alertList" type="{{alert.type}}" close="closeAlert(alertList, $index)">{{alert.msg}}</div>

How to include/inject functions which use $scope into a controller in angularjs?

I am trying to include a library of functions, held in a factory, into a controller.
Similar to questions like this:
Creating common controller functions
My main controller looks like this:
recipeApp.controller('recipeController', function ($scope, groceryInterface, ...){
$scope.groceryList = [];
// ...etc...
/* trying to retrieve the functions here */
$scope.groceryFunc = groceryInterface; // would call ng-click="groceryFunc.addToList()" in main view
/* Also tried this:
$scope.addToList = groceryInterface.addToList();
$scope.clearList = groceryInterface.clearList();
$scope.add = groceryInterface.add();
$scope.addUp = groceryInterface.addUp(); */
}
Then, in another .js file, I have created the factory groceryInterface. I've injected this factory into the controller above.
Factory
recipeApp.factory('groceryInterface', function(){
var factory = {};
factory.addToList = function(recipe){
$scope.groceryList.push(recipe);
... etc....
}
factory.clearList = function() {
var last = $scope.prevIngredients.pop();
.... etc...
}
factory.add = function() {
$scope.ingredientsList[0].amount = $scope.ingredientsList[0].amount + 5;
}
factory.addUp = function(){
etc...
}
return factory;
});
But in my console I keep getting ReferenceError: $scope is not defined
at Object.factory.addToList, etc. Obviously I'm guessing this has to do with the fact that I'm using $scope in my functions within the factory. How do I resolve this? I notice that in many other examples I've looked at, nobody ever uses $scope within their external factory functions. I've tried injecting $scope as a parameter in my factory, but that plain out did not work. (e.g. recipeApp.factory('groceryInterface', function(){ )
Any help is truly appreciated!
Your factory can't access your $scope, since it's not in the same scope.
Try this instead:
recipeApp.controller('recipeController', function ($scope, groceryInterface) {
$scope.addToList = groceryInterface.addToList;
$scope.clearList = groceryInterface.clearList;
$scope.add = groceryInterface.add;
$scope.addUp = groceryInterface.addUp;
}
recipeApp.factory('groceryInterface', function () {
var factory = {};
factory.addToList = function (recipe) {
this.groceryList.push(recipe);
}
factory.clearList = function() {
var last = this.prevIngredients.pop();
}
});
Alternatively, you can try using a more object oriented approach:
recipeApp.controller('recipeController', function ($scope, groceryInterface) {
$scope.groceryFunc = new groceryInterface($scope);
}
recipeApp.factory('groceryInterface', function () {
function Factory ($scope) {
this.$scope = $scope;
}
Factory.prototype.addToList = function (recipe) {
this.$scope.groceryList.push(recipe);
}
Factory.prototype.clearList = function() {
var last = this.$scope.prevIngredients.pop();
}
return Factory;
});
You cannot use $scope in a factory as it is not defined. Instead, in your factory functions change the properties of the object the factory is returning, e.g.
factory.addToList = function (recipe) {
this.groceryList.push(recipe);
}
these will then get passed on to your $scope variable
$scope.addToList = groceryInterface.addToList;
// ... = groceryInterface.addToList(); would assign to `$scope.addToList` what is returned, instead of the function itself.
This isn't the exact answer for this question, but I had a similar issues that I solved by simply passing $scope as an argument to a function in my factory. So it won't be the normal $scope, but $scope at the time the function in the factory is called.
app.controller('AppController', function($scope, AppService) {
$scope.getList = function(){
$scope.url = '/someurl'
// call to service to make rest api call to get data
AppService.getList($scope).then(function(res) {
// do some stuff
});
}
});
app.factory('AppService', function($http, $q){
var AppService = {
getList: function($scope){
return $http.get($scope.url).then(function(res){
return res;
});
},
}
return AppService;
});

Categories