Pass value from one controller to another in angular js1 - angularjs

I am using $rootScope for passing value from one controller to another but i did not get the value in second controller(cart).
x.controller("first",function($scope,$http,$rootScope){
$scope.cart1=function(x,y){
$rootScope.img=x;
$rootScope.login=y;
}
});
x.controller("cart",function($scope,$rootScope){
$scope.cart2=$rootScope.img;
console.log($scope.cart2)
});

$rootScope does not get the value assigned if you simply define in controller, you need to transfer the data from controller1 to controller2 based on some event
DEMO
var x =angular.module('app', [])
x.controller("first",function($scope,$rootScope){
$scope.cart1=function(x,y){
console.log(x);
$rootScope.img=x;
$rootScope.login=y;
}
});
x.controller("cart",function($scope,$rootScope){
$scope.getData=function(){
$scope.cart2=$rootScope.img;
console.log($scope.cart2)
};
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#1.4.3" data-semver="1.4.3" src="https://code.angularjs.org/1.4.3/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body >
<div ng-controller="first">
<button ng-click="cart1('test','test2')">transfer</button>
</div>
<div ng-controller="cart">
<button ng-click="getData()">getStoredValue</button>
{{cart2}}
</div>
</body>
</html>
NOTE
Using $rootScope is not a recommended way to transfer variable across controllers, instead try using services.

why not using $broadcast, considering your controller structure $scope.$parent is enough, in oter case inject $rootScope from where you are firing the $broadcast
var x =angular.module('app', [])
x.controller("first",function($scope){
$scope.cart1=function(x,y){
$scope.$parent.$broadcast('value changed', {x: X, y: y});
}
});
x.controller("cart",function($scope){
$scope.$on('value changed', function(data){
$scope.login = x;
$scope.cart2 = y;
});
});
Now your values are set in scope, use it whenever needed (in case of binding it will automatically reflect in UI)

(function() {
"use strict";
angular
.module('app')
.factory("cartFactory", cartFactory);
function cartFactory($http) {
return {
login: '',
cart2:''
};
}})();
This is your factory
you can use multiple controller like this...
var x =angular.module('app', [])
x.controller("first",function($scope,cartFactory){
cartFactory.login=x;
cartFactory.cartFactory=y;
}
});
x.controller("cart",function($scope,cartFactory){
$scope.login = cartFactory.login;
$scope.cart2 = cartFactory.cart2;
});
This is very simple to pass data one controller to another multiple controller.

Related

Angularjs TypeError: is not a function issue

I have a select that calls a controller in a directive, that in turn calls a function from a service when the user selects a value in the dropdown list. For some reason I'm getting this error:
TypeError: myService.getMessage is not a function
So I created a plunker to pull out the basic functionality and I was able to duplicate the error using a controller to call a basic service, but I'm still not solving it yet.
Here is the code:
HTML Code:
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.2.x" src="https://code.angularjs.org/1.2.22/angular.js" data-semver="1.2.22"></script>
<script src="script.js"></script>
</head>
<body ng-controller="MainCtrl">
<select ng-options="option for option in listOfOptions"
ng-model="selectedItem"
ng-change="selectedItemChanged()">
</select>
<p>This is the selected Item from the model: <b>{{selectedItem}}</b></p>
<p>This is the result of the ng-change function: <b>{{calculatedValue}}</b></p>
</body>
Script Code:
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope, myService) {
$scope.listOfOptions = ['One', 'Two', 'Three'];
$scope.selectedItemChanged = function(){
$scope.calculatedValue = 'You selected number ' + $scope.selectedItem;
//Call the service.
myService.getMessage();
}
});
app.service('myService', function(){
function getMessage(){
alert("You are in myService!");
}
});
I've seen lots of different, much more complicated code for this type of error, but I'm not understanding what is causing this? Any ideas as to the proper way to do this?
What I'm trying to do is to use a function like myService.mySearch(param1) from a controller or directive.
wrong service code, should be:
app.service('myService', function() {
this.getMessage = function() {
alert("You are in myService!");
}
});
.service() is a function which takes a name and a function that defines the service.It acts as a constructor function.We can inject and use that particular service in other components : controllers, directives and filters.
Correct Syntax :
app.service('myService', function(){
this.getMessage = function(){
alert("You are in myService!");
}
});
Main thing is that service is a constructor function. Hence, we can work with this keyword. In background, this code calls Object.create() with the service constructor function, when it gets instantiated.
In addition to Fetra R 's answer,
Factory is mostly preferable in all cases. It can be used when you have constructor function which needs to be instantiated in different controllers. Service is a kind of Singleton Object. The Object return from Service will be same for all controller.
So as it is like a singleton object, you have to declare it as The Fetra R's Answer, or You may write a factory.
app.factory('myService', function() {
return {
getMessage: function() {
alert("You are in myService!");
}
}
});
and use it in the same manner.

AngularJS - two way binding not working using service

I am learning Angular using W3Schools.
I just modified an example about "Services"... The following is the code:
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<p><input type="text" ng-model="num"></p>
<h2>{{num}}</h2>
<h1>{{hex}}</h1>
</div>
<p>A custom service whith a method that converts a given number into a hexadecimal number.</p>
<script>
var app = angular.module('myApp', []);
app.service('hexafy', function() {
this.myFunc = function (x) {
return x.toString(16);
}
});
app.controller('myCtrl', function($scope, hexafy) {
$scope.num = 200;
$scope.hex = hexafy.myFunc($scope.num);
});
</script>
</body>
</html>
When I update the textbox, the "HEX" part is not updating. Why?
Your hexafy.myFunc is called only once when the controller is initialized, hence only the initial value is converted to hex. If you want a function to be called on the value change of a scope variable in runtime, you need filters. AngularJS has a lot of inbuilt filters that are ready to use.
You can also define a custom filter, just like you define services or controllers.
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<p><input type="text" ng-model="num"></p>
<h2>{{num}}</h2>
<h1>{{num | hexafy}}</h1>
</div>
<p>A custom filter that converts a given number into a hexadecimal number.</p>
<script>
var app = angular.module('myApp', []);
app.filter('hexafy', function() {
return function (x) {
return Number(x).toString(16); // Also convert the string to number before calling toString.
}
});
app.controller('myCtrl', function($scope) {
$scope.num = 200;
//$scope.hex = hexafy.myFunc($scope.num);
});
</script>
</body>
</html>
Further reading: AngularJS Filters
NOTE: A filter is a good idea if you're gonna be using the hexafy functionality at multiple places in/across views. Otherwise, it is just an overkill and the $scope.$watch method will work fine for you, as described in other answers
$scope.hex is not updating because there're no way for it update itself.
The hexafy.myFunc is called only once when the controller is loaded for the first time.
If you want want the $scope.hex property to change with num, you might need a watch on the num property.
$scope.$watch('num', function(newVal, oldVal) {
$scope.hex = hexafy.myFunc($scope.num); /// or newVal
}
The function passed in $scope.$watch will be called everytime the value of $scope.num changes.
for more info see https://docs.angularjs.org/api/ng/type/$rootScope.Scope (the watch section)
Hope it helps.
No need of a service here, you can simple use $watch on the num. See below code snippet, it will update your ui, I have updated your controller code, please check.
app.controller('myCtrl', function($scope, hexafy) {
$scope.num = 200;
$scope.hex = "some default val";
$scope.$watch('num', function(newValue, oldValue) {
$scope.hex = newValue.toString();
});
});
Your Text box is only bind to 'num'. '$scope.hex is not binded to your text box'. So that it is not update when you typing text. You could use '$watch' on 'num'. Read here
app.controller('myCtrl', function($scope, hexafy) {
$scope.num = 200;
$scope.$watch('num', function() {
$scope.hex = hexafy.myFunc(parseInt($scope.num));
});
});

Why doesn't ng-hide/show work if expression is a scope variable modified on broadcast event

I have the following code:
script.js:
var app = angular.module('TestApp',[]);
app.factory('testfactory', function($rootScope, $window){
var factory = {};
factory.auth = function() {
//This is only to make call to auth() async.
//Actual code is using google-api call.
setTimeout(auth, 2000);
}
$window.auth = function(){
$rootScope.$broadcast('loggedin');
}
return factory;
});
app.controller('MainCtrl', function($scope, testfactory) {
$scope.status = {
loggedIn: false
}
$scope.test = testfactory;
$scope.$on('loggedin', function(){
$scope.status.loggedIn = true;
alert('loggedIn');
});
});
index.html:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" />
</head>
<body ng-app="TestApp">
<div ng-controller="MainCtrl">
<button ng-click="test.auth()" ng-hide="status.loggedIn">Auth</button>
</div>
<script data-require="angular.js#1.2.19" data-semver="1.2.19" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.min.js"></script>
<script src="script.js"></script>
</body>
</html>
This should hide the button "Auth" on clicking, however it does not. It works only when its clicked the second time. What's happening here? I'm modifying the scope variable inside angular's broadcasted event, so binding should work. What am I missing here?
Edit: I know wrapping the code within $scope.$apply works, but my question is why isn't it happening automatically, since I'm not modifying the variable from outside the scope.
Here's a plunker for this code - http://plnkr.co/edit/Ov568VDWCKarFHQjgbvG
Answer: This discussion on google groups says $broadcast doesn't trigger auto-apply. So, if $broadcast is called from outside of angular-world, $apply must be applied manually.
Because Angular use $digest (documentation, and why/where to use) to keep the binding between the $scope and the interface. Try to force the $digest:
$scope.$on('loggedin', function(){
$scope.status.loggedIn = true;
$scope.digest();
alert('loggedIn');
});
or
$scope.$on('loggedin', function(){
$scope.apply(function(){
$scope.status.loggedIn = true;
});
alert('loggedIn');
});
Edit:
why isn't it happening automatically ?
The setTimeout function runs outside the angular scope, therefore angular has no idea that you might change something.
You could also solve the problem with the #pixelbits solution. The $timeout service is just a wrapper around javascript's setTimeout witch executes within the angular scope.
http://plnkr.co/edit/o3XtMLpCquHcU2j2z4v9?p=preview
please add $scope.$apply();
app.controller('MainCtrl', function($scope, testfactory) {
$scope.status = {
loggedIn: false
}
$scope.test = testfactory;
$scope.$on('loggedin', function()
{
$scope.status.loggedIn = true;
$scope.$apply();
alert('loggedIn');
});
});
Use $timeout instead of setTimeout. $timeout will trigger a $digest cycle, but setTimeout will not:
$timeout(auth,2000);

$rootscope object model from service not (always) available in every controller

In my app definition I have:
var myVtModule = angular.module('vtApp', ['myAppDev','mongoAPI']);
myVtModule.run(function($rootScope, $location, Shop){
$rootScope.shopData = {};
Shop.getShop(function(response){
$rootScope.shopData = response;
});
})
Shop is a service retrieving data from server, it works. The problem is that in the controller I don't always have access to shopData, sometimes is empty, sometimes is working normally.
function SupportCtrl($rootScope, $scope) {
console.log ($rootScope.shopData);
}
Why is not updating when it receives the response from the service? I can't put the Shop.getShop in the controller as I need it everywhere...
My suggestion would be to use controller inheritance and a service so that your child controllers can always have access to the shop. Here is a demo:
http://beta.plnkr.co/edit/DtjwLMi3jHCdzThEJDNn?p=preview
Code:
angular.module('myApp', ['myApp.services']);
function MainCtrl($scope, ShopService) {
$scope.shop = ShopService.getShop();
}
function ChildCtrl($scope) {
}
angular.module('myApp.services', []).
factory('ShopService', function ($rootScope) {
var shop = {
storename: 'your store'
};
var service = {
getShop: function() {
return shop;
}
}
return service;
});
HTML that sets up the child controller relationship:
<html ng-app="myApp" >
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<link rel="stylesheet" href="style.css">
<script>document.write("<base href=\"" + document.location + "\" />");</script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
The store is {{shop.storename}}
<div ng-controller="ChildCtrl">
The store name is: {{shop.storename}}
</div>
</body>
</html>
You will notice that the shop is available to the child because the parent scope retrieved it. I set up the service so you can make it testable/etc. Besides the inheritance you could just as easily inject the ShopService into each controller and have them make the call, but if you have a lot of controllers that could become tedious.
Some more info on scope inheritance:
can i inherit a parent controller's variables?
http://docs.angularjs.org/guide/dev_guide.mvc.understanding_controller
If you need the results in your controller, you should skip myVtModule.run and do something like this instead:
function SupportCtrl($scope, Shop) {
Shop.getShop(function(response){
console.log (response);
//do something, put response in $scope or $scope.$rootScope etc...
});
}
Your ng-controller scopes all prototypically inherit from rootScope (eventually), so they all have access to any objects you define on rootScope. Since retrieving data from a server is an asynchronous operation, your controllers may execute before the server data is returned.
You can use $watch in your controllers to determine when the data is actually available. However, if you just want your views to update when the data becomes available, you don't have to use $watch. Angular should automatically update your views when the data becomes available. E.g.,
function SupportCtrl($rootScope, $scope) {
$scope.shopData = $rootScope.shopData;
}
Then in your view:
<div ng-controller="SupportCtrl">shopData = {{shopData}}</div>
Fiddle - I simulated a server delay using $timeout. Note that in the fiddle I also use angular.copy() to update the reference the controller has, rather than assigning $rootScope.shopData to a new/different array:
app.run(function($rootScope, $timeout){
$rootScope.shopData = [];
$timeout(function() {
angular.copy([{d1: 'data1', d2: 'data2'}], $rootScope.shopData);
}, 2000);
});

Template preparation in AngularJs

Is it possible to render template with AngularJs not on Page, but probably in memory? I need to prepare html to be send as email.
I guess i could render something in hidden div, then in some way assign it content to variable , but for me it looks ugly :(
You can take a look at $compile function: http://docs.angularjs.org/api/ng.$compile
Example:
function MyCtrl($scope, $compile){
// You would probably fetch this email template by some service
var template = '</div>Hi {{name}}!</div></div>Here\'s your newsletter ...</div>'; // Email template
$scope.name = 'Alber';
// this produces string '</div>Hi Alber!</div></div>Here\'s your newsletter ...</div>'
var compiledTemplate = $compile(template)($scope);
};
Sure, you can use the $compile service to render a template. The rendered template will be a DOM node that isn't attached to the DOM tree. And you don't have to attach it to get its content. You could do something like this:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.controller('MainCtrl', ['$scope', '$compile', function($scope, $compile){
var compiled;
$scope.compileTemplate = function() {
var template = '<ul><li ng-repeat="i in [1, 2, 3]">{{i}}</li></ul>';
var linker = $compile(template);
compiled = linker($scope);
}
$scope.sendEmail = function() {
alert("Send: " + compiled[0].outerHTML);
}
}]);
</script>
</head>
<body ng-controller="MainCtrl">
<button ng-click="compileTemplate()">Compile template</button>
<button ng-click="sendEmail()">Send email</button>
</body>
</html>
The reason that I've divided them into two different functions here is because when you compile and link it to the scope, the template isn't filled with data until after the next digest. That is, if you access compiled[0].outerHTML at the end of the compileTemplate() function, it won't be filled (unless you use a timeout...).

Resources