Angular: Updating different controller through service or better method - javascript

I have a UserService
angular.module('mango.services', [])
.factory('UserService', function() {
var user = {
id: null,
name: 'anonymous.'
};
function getUser(){
return user;
}
function setUser(val){
user = val;
}
return {
getUser: getUser,
setUser: setUser,
}
});
a NavbarController
.controller('NavbarController', ['$scope','$location','UserService', function($scope, $location, UserService){
$scope.isActive = function (viewLocation) {
return viewLocation === $location.path();
};
$scope.username = UserService.getUser().name;
}])
and a UserController where I have registerUser and loginUser functions.
.controller('UserController', ['$scope', '$http', 'UserService', function($scope, $http, UserService) {
$scope.loginUser = function(){
$http.post('/api/1.0/user/authenticate', $scope.user)
.success(function(data,status,headers,config){
if (data["valid"] === true) {
UserService.setUser(data.user);
} else {
$scope.flashes = data.flashes;
$scope.user.password = "";
}
})
}
and the HTML
<li ng-switch="username">
<a ng-class="{ active: isActive('/user/login')}" href="#/user/login" ng-switch-when="anonymous."><i class="fa fa-sign-in"></i> Sign in</a>
<a ng-class="{ active: isActive('/user/logout')}" href="#/user/logout" ng-switch-default><i class="fa fa-sign-out"></i> Sign out</a>
</li>
As you can see I'm trying to set the user of UserService if data.valid is true.
The server is returning a valid json object.
But the username value in NavbarController remains "anonymous." .
I'm not very experienced in JS, but I read something about broadcast and watch. I believe this might be the right approach. But maybe there's a better one.
I believe why it's not working is because the factory returns a singleton. But then using a factory is pointless.
So essentially what I want is, if credentials valid set user.name user.id client-app-wide. Later it should go through an "check if client user is valid" service. My session cookie is encrypted. But that's out of scope of the question.
All I need right now is to set the app's or rather the NavbarController's user data from UserController. How do I do that so it also updates the DOM aka ng-switch getting a different value.

It is not working because you are not creating a binding of some kind: with $scope.username = UserService.getUser().name you get the user name at that instant of time (which is anonymous) and hold on to it forever. One way out of this is with a watch. In NavbarController, replace the previous code with:
$scope.$watch(
function() {
return UserService.getUser().name;
},
function(newval) {
$scope.username = newval;
}
);
This will incur your application with a function call in every digest cycle. This function call is not slow, so it wouldn't matter.
If you do not want this overhead, you can also do it with events. In NavbarController:
$scope.username = UserService.getUser().name;
$scope.on("loggedIn", function(event, newUserName) {
$scope.username = newUserName;
});
And in UserController (add $rootScope to the dependencies):
if (data["valid"] === true) {
UserService.setUser(data.user);
$rootScope.$broadcast("loggedIn", data.user);
}

You indeed do need a $watcher to sync username in the NavbarController and UserService instead of $scope.username = UserService.getUser().name; which only sets up the initial value of $scope.username when the Controller is initialised:
$scope.$watch(
function () { return UserService.getUser().name; },
function (newVal) {
$scope.username = newVal;
}
);
The factory indeed designed to be a singleton across the application and that is the place where you should save the state of the application (i.e. your models, like the User model). The controllers are ephemeral and are created anew each time a template is created.
However, if you have a long lived Controller (like your NavbarControll), then the onus of maintaining a sync between the services and the controller is on the programmer using $watch.
Broadcasting messages is useful in some cases when inter-controller communication (which does not necessarily involve the models) is needed.

You can same approach without using $watch.
I have written a short function that let you put data in Object without replace it.
You can use it in you service. This way youu don't need to use watch. You can use the normal digest loop of Angular.
For example, see this simple controller & service:
Demo: JSFidde - http://jsfiddle.net/y09kx7f7/1/ with assert tests
Controller:
app.controller('dem',function($scope,me){
$scope.user=me.user; // {name:'user name'}
})
The controller will be chnage automatically without watch every time the user name changed!
Service
.factory('me',function($timeout){
var obj={}
obj.user={name:'hello'}
$timeout(function(){ //Example of change the data
newUser={name:'israel'}
cloneInto(obj.user,newUser)
},1000)
return obj
})
The cloneInto function that I written:
// The function it is like a=b,
// but keeping the object in his original memory position.
function cloneInto(a,b){
var i
for (i in a){
if(typeof a[i]!='object') //For supporting deep-copy
delete a[i]
}
for (i in b){
if (typeof b[i]=='object'){
if(!a[i]) a[i]={}
cloneInto(a[i],b[i])
}
else{
a[i]=b[i]
}
}
}

Related

How to force view updates in angularjs by services?

I'm trying to hold a global MainCtrl controller that serves the navigation menus. From time to time these menu items should be updated by various controllers.
Now I thought I might just bind the navigation links to the controller, and update the controller variable as follows:
<div ng-controller="MainCtrl">
<li ng-repeat="nav in navigations">
{{nav.label}}
</li>
</div>
<div ng-view></div> <!-- renders different controllers, eg testController.js -->
app.controller('MainCtrl', ['$scope', 'navigationService', function($scope, navigationService) {
//binding the property of the service
$scope.navigations = navigationService.navigations;
}]);
app.service('navigationService', function() {
return {
navigations: null
};
});
But, when calling the service and updating the navigations variable inside, nothing is changed in the view. Why?
angular.module('test').controller('testController', ['$scope', '$http', 'navigationService', function($scope, $http, navigationService) {
$http.get(url)
.success(function(data) {
navigationService.navigations = data.some.navigations; //assume json data exists
});
}]);
How can I achieve this two-way databinding, forcing a view update from one controller to another?
You are returning a primitive from service. A primitive doesn't have inheritance.
Return an object instead:
app.service('navigationService', function() {
var nav ={}; // object that will be returned
function init(){
$http.get(url)
.success(function(data) {
// modify object returned from service rather than reassign a primitive value
nav.items = data.some.navigations; exists
});
}
init();//make request to load the data
return { // can add more properties if needed
nav: nav
};
});
Then in controller:
$scope.navigations = navigationService.nav;
// will initially be {} and later will inherit items property
In view
<div ng-repeat="item in navigations.items">
angular internal watches will pick up the changes now made to the object and render view accordingly
After using Angular for more than 2 years, I discovered, whenever you want that functionality with multiple binding from different services/controllers/directives, ALWAYS use json property, and NEVER ovverride variable instance:
I would replace that:
$scope.navigations = navigationService.navigations;
with that:
var state = {
navigations: []
};
$scope.state = state;
state.navigations = navigationService.navigations; // i prefer such syntax
// or
$scope.state.navigations = navigationService.navigations;
Why? Probably because of Angular automatic $watch()/$watchCollection() functions, which are bind to variable changes.
You need to use the $rootscope and broadcast to and keep eye on broadcast
Say your data is changed from x controller, so here you can broadcast like this
$rootScope.$broadcast('menu-need-to-refresh');
In your main controller keep eye, like this
$scope.$on('menu-need-to-refresh', function (event, data) {
$scope.menus= service.newMenu();
});
Hope it will help you
I solved a similar problem simply by using $scope.$watch
ex:
$scope.$watch(
function(){return navigationService.navigations;},
function(newVal, oldVal){$scope.navigations = newVal;}
)
this code is not tested, but you get the gist
Update : #charlietfl + #Dmitri Algazin method is more elegant as it takes advantage of javascript itself, by using references, and avoid using two watchers in controller + ngRepeat (watchCollection in this directive will do the work).
My original answer :
You should watch for changes in the service from MainCtrl using $scope.$watch :
app.controller('MainCtrl', ['$scope', 'navigationService', function($scope, navigationService) {
//binding the property of the service
$scope.$watch(
function(){
return navigationService.navigations;
}
, function(newValue, oldValue){
if(newValue !== oldValue){
$scope.navigations = newValue;
}
})
}]);

Angular binding to service value not updating

I cannot get a binded service value to update when it is changed. I have tried numerous methods of doing so but none of them have worked, what am I doing wrong? From everything I have seen, this seems like it should work...
HTML:
<div class="drawer" ng-controller="DrawerController">
{{activeCountry}}
</div>
Controller:
angular.module('worldboxApp')
.controller('DrawerController', ['$scope', 'mapService', function($scope, mapService) {
$scope.$watch(function() { return mapService.activeCountry }, function(newValue, oldValue) {
$scope.activeCountry = mapService.activeCountry;
});
}]);
Service:
angular.module('worldboxApp').
service('mapService', function(dbService, mapboxService, userService) {
this.init = function() {
this.activeCountry = {};
}
this.countryClick = function(e) {
this.activeCountry = e.layer.feature;
};
this.init();
});
I put a break point to make sure the mapService.activeCountry variable is being changed, but all that ever shows in the html is {}.
If you work with objects and their properties on your scope, rather than directly with strings/numbers/booleans, you're more likely to maintain references to the correct scope.
I believe the guideline is that you generally want to have a '.' (dot) in your bindings (esp for ngModel) - that is, {{data.something}} is generally better than just {{something}}. If you update a property on an object, the reference to the parent object is maintained and the updated property can be seen by Angular.
This generally doesn't matter for props you're setting and modifying only in the controller, but for values returned from a service (and that may be shared by multiple consumers of the service), I find it helps to work with an object.
See (these focus on relevance to ngModel binding):
https://github.com/angular/angular.js/wiki/Understanding-Scopes
If you are not using a .(dot) in your AngularJS models you are doing it wrong?
angular.module('worldboxApp', []);
/* Controller */
angular.module('worldboxApp')
.controller('DrawerController', ['$scope', 'mapService',
function($scope, mapService) {
//map to an object (by ref) rather than just a string (by val), otherwise it's easy to lose reference
$scope.data = mapService.data;
$scope.setCountry = setCountry; //see below
function setCountry(country) {
// could have just set $scope.setCountry = mapService.setCountry;
// however we can wrap it here if we want to do something less generic
// like getting data out of an event object, before passing it on to
// the service.
mapService.setCountry(country);
}
}
]);
/* Service */
angular.module('worldboxApp')
.service('mapService', ['$log',
function($log) {
var self = this; //so that the functions can reference .data; 'this' within the functions would not reach the correct scope
self.data = {
activeCountry: null
}; //we use an object since it can be returned by reference, and changing activeCountry's value will not break the link between it here and the controller using it
_init();
function _init() {
self.data.activeCountry = '';
$log.log('Init was called!');
}
this.setCountry = function _setCountry(country) {
$log.log('setCountry was called: ' + country);
self.data.activeCountry = country;
}
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
<div ng-app="worldboxApp">
<div ng-controller="DrawerController">
<button ng-click="setCountry('USA')">USA</button>
<br />
<button ng-click="setCountry('AUS')">AUS</button>
<br />Active Country: {{data.activeCountry}}
</div>
</div>
In some case $watch is not working with factory object. Than you may use events for updates.
app.factory('userService',['$rootScope',function($rootScope){
var user = {};
return {
getFirstname : function () {
return user.firstname;
},
setFirstname : function (firstname) {
user.firstname = firstname;
$rootScope.$broadcast("updates");
}
}
}]);
app.controller('MainCtrl',['userService','$scope','$rootScope', function(userService,$scope,$rootScope) {
userService.setFirstname("bharat");
$scope.name = userService.getFirstname();
$rootScope.$on("updates",function(){
$scope.name = userService.getFirstname();
});
}]);
app.controller('one',['userService','$scope', function(userService,$scope) {
$scope.updateName=function(){
userService.setFirstname($scope.firstname);
}
}]);
Here is the plunker
Note:- In Some case if broadcast event is not fired instantly you may use $timeout. I have added this in plunker and time depends on your needs. this will work for both factories and services.

Can't access $rootScope from another controller

Why can't I access the $rootScope, particulary the currentUser object and the signedIn() function from the RegistrationController?
I'm trying to follow a tutorial example and I'm able to sucessfully set the $rootScope.currentUser variable in a service (Authentication), but when I try to access it from another controller (RegistrationController) I cannot access it.
My understanding is that $rootScope is kind of a global variable that is accessible from all the app, is this correct?
myApp.controller('RegistrationController',
function($scope, $firebaseAuth, $location, Authentication, $rootScope){
$scope.login = function() {
Authentication.login($scope.user)
.then(function(userReturned){
console.log('registration.js: logged in user '+userReturned.uid);
//console.log('registration.js: $rootScope.currentUser ahora es... ');
//console.log($rootScope.currentUser);
$location.path('/meetings');
})
.catch(function(error) {
$scope.message = error.toString();
});
} //login
}); //RegistrationController
myApp.factory('Authentication',
function($firebase, $firebaseAuth, FIREBASE_URL, $location, $rootScope) {
// using $firebaseAuth instead of SimpleLogin
var ref = new Firebase(FIREBASE_URL);
var authObj = $firebaseAuth(ref);
var myObject = {
login : function(user) {
return authObj.$authWithPassword({
email: user.email,
password: user.password
})
.then(function(authData){
console.log('authentication.js: logged in user '+ authData.uid);
var userRef = new Firebase(FIREBASE_URL + 'users/' + authData.uid);
var userObj = $firebase(userRef).$asObject();
userObj.$loaded().then(function() {
$rootScope.currentUser = userObj;
});
$rootScope.$broadcast('$firebaseAuth:authWithPassword',authData); // avisa al scope
return authData;
});
}, //login
signedIn: function() {
//console.log(authObj);
//console.log('authentication.js: signedIn function called and returned '+ (authObj.user != null) );
return authObj.user != null;
} // signedIn
} //myObject
// add signedIn to the $rootScope
$rootScope.signedIn = function() {
return myObject.signedIn();
}
return myObject;
});
I believe what's happening is the promise Authentication.login is being resolved before currentUser being set $rootScope.currentUser = userObj;
to make sure this is the case, try put a breakpoint on this line in your Authentication service:
$rootScope.currentUser = userObj;
and another breakpoint on this one in your controller:
console.log($rootScope.currentUser);
and see which one is being executed before the other.
IF this is the case, try this:
Move the block of code in [THEN] statement from your service to your controller, where you are treating the current user and logging it.
It looks like you're trying to print $rootScope.currentUser from RegistrationController.login(). But currentUser was never set on $rootScope. Here's an example that demonstrates using $rootScope on two controllers.
angular.module('Main', [])
.controller("SetCtrl", function($scope, $rootScope) {
$scope.name = 'abc';
$rootScope.copy = $scope.name;
})
.controller("GetCtrl", function($scope, $rootScope) {
$scope.fromSetCtrl = $rootScope.copy;
});
http://plnkr.co/edit/dj6Y9hIEJ3KA9yAjuQP5
I'm not exactly sure how your are using your service/factory and how your apps and controllers are set up.
I think $rootScope is the "top" scope of the outermost controller of your app. You can have a $rootScope for each of your "app".
I would guess that if you set a variable in the $rootScope in the service in one of your app and then try to access your service from the $rootScope from the controller from ANOTHER app, you will not be able to find the variable because it is in another $rootScope. In that sense $rootScope is NOT a global variable.
You can access $rootScope variables directly from the child controllers if you pass in "$rootScope" when you define your controller, or from indirectly from $scope of the child controllers, because angular will look for the variable from the current controller's scope all the way up to that controller's $rootScope.
Hope this helps.

Loading one dataset using data from another in Angular $watch

I am creating a messaging service that needs to do the following 1.) Load a messsage from our messages service, get the recipient's ids, and then load the recipients' info from a users service. I've tried both using the messages service callback, and also creating a watcher on the message object, without much success. The service works, but it doesn't assign the result to the $scope correctly. Here's the controller. All of the services are working correctly:
function MessageCtrl ($scope, $http, $location, $routeParams, Messages, Members) {
if ($routeParams.mid) { // Checks for the id of the message in the route. Otherwise, creates a new message.
$scope.mid = $routeParams.mid;
$scope.message = Messages.messages({mid: $scope.mid}).query();
$scope.$watch("message", function (newVal, oldVal, scope) {
if (newVal.data) {
$scope.recipients = Members.members({uids: newVal.data[0].uids}).query();
}
}, true);
} else {
$scope.create = true;
}
// Events
$scope.save = function () { };
$scope.preview = function () { };
$scope.send = function () { };
}
The correct way to use query is to perform the action in the callback that is passed in query function. In other words$scope.message should be assigned in the callback. Also you don't need a $watch. You can call the other service within the callback directly. But to keep it clean please use deferred
http://docs.angularjs.org/api/ngResource.$resource
http://docs.angularjs.org/api/ng.$q

Maintain model of scope when changing between views in AngularJS

I am learning AngularJS. Let's say I have /view1 using My1Ctrl, and /view2 using My2Ctrl; that can be navigated to using tabs where each view has its own simple, but different form.
How would I make sure that the values entered in the form of view1 are not reset, when a user leaves and then returns to view1 ?
What I mean is, how can the second visit to view1 keep the exact same state of the model as I left it ?
I took a bit of time to work out what is the best way of doing this. I also wanted to keep the state, when the user leaves the page and then presses the back button, to get back to the old page; and not just put all my data into the rootscope.
The final result is to have a service for each controller. In the controller, you just have functions and variables that you dont care about, if they are cleared.
The service for the controller is injected by dependency injection. As services are singletons, their data is not destroyed like the data in the controller.
In the service, I have a model. the model ONLY has data - no functions -. That way it can be converted back and forth from JSON to persist it. I used the html5 localstorage for persistence.
Lastly i used window.onbeforeunload and $rootScope.$broadcast('saveState'); to let all the services know that they should save their state, and $rootScope.$broadcast('restoreState') to let them know to restore their state ( used for when the user leaves the page and presses the back button to return to the page respectively).
Example service called userService for my userController :
app.factory('userService', ['$rootScope', function ($rootScope) {
var service = {
model: {
name: '',
email: ''
},
SaveState: function () {
sessionStorage.userService = angular.toJson(service.model);
},
RestoreState: function () {
service.model = angular.fromJson(sessionStorage.userService);
}
}
$rootScope.$on("savestate", service.SaveState);
$rootScope.$on("restorestate", service.RestoreState);
return service;
}]);
userController example
function userCtrl($scope, userService) {
$scope.user = userService;
}
The view then uses binding like this
<h1>{{user.model.name}}</h1>
And in the app module, within the run function i handle the broadcasting of the saveState and restoreState
$rootScope.$on("$routeChangeStart", function (event, next, current) {
if (sessionStorage.restorestate == "true") {
$rootScope.$broadcast('restorestate'); //let everything know we need to restore state
sessionStorage.restorestate = false;
}
});
//let everthing know that we need to save state now.
window.onbeforeunload = function (event) {
$rootScope.$broadcast('savestate');
};
As i mentioned this took a while to come to this point. It is a very clean way of doing it, but it is a fair bit of engineering to do something that i would suspect is a very common issue when developing in Angular.
I would love to see easier, but as clean ways to handle keeping state across controllers, including when the user leaves and returns to the page.
A bit late for an answer but just updated fiddle with some best practice
jsfiddle
var myApp = angular.module('myApp',[]);
myApp.factory('UserService', function() {
var userService = {};
userService.name = "HI Atul";
userService.ChangeName = function (value) {
userService.name = value;
};
return userService;
});
function MyCtrl($scope, UserService) {
$scope.name = UserService.name;
$scope.updatedname="";
$scope.changeName=function(data){
$scope.updateServiceName(data);
}
$scope.updateServiceName = function(name){
UserService.ChangeName(name);
$scope.name = UserService.name;
}
}
$rootScope is a big global variable, which is fine for one-off things, or small apps.
Use a service if you want to encapsulate your model and/or behavior (and possibly reuse it elsewhere). In addition to the google group post the OP mentioned, see also https://groups.google.com/d/topic/angular/eegk_lB6kVs/discussion.
Angular doesn't really provide what you are looking for out of the box. What i would do to accomplish what you're after is use the following add ons
UI Router & UI Router Extras
These two will provide you with state based routing and sticky states, you can tab between states and all information will be saved as the scope "stays alive" so to speak.
Check the documentation on both as it's pretty straight forward, ui router extras also has a good demonstration of how sticky states works.
I had the same problem, This is what I did:
I have a SPA with multiple views in the same page (without ajax), so this is the code of the module:
var app = angular.module('otisApp', ['chieffancypants.loadingBar', 'ngRoute']);
app.config(['$routeProvider', function($routeProvider){
$routeProvider.when('/:page', {
templateUrl: function(page){return page.page + '.html';},
controller:'otisCtrl'
})
.otherwise({redirectTo:'/otis'});
}]);
I have only one controller for all views, but, the problem is the same as the question, the controller always refresh data, in order to avoid this behavior I did what people suggest above and I created a service for that purpose, then pass it to the controller as follows:
app.factory('otisService', function($http){
var service = {
answers:[],
...
}
return service;
});
app.controller('otisCtrl', ['$scope', '$window', 'otisService', '$routeParams',
function($scope, $window, otisService, $routeParams){
$scope.message = "Hello from page: " + $routeParams.page;
$scope.update = function(answer){
otisService.answers.push(answers);
};
...
}]);
Now I can call the update function from any of my views, pass values and update my model, I haven't no needed to use html5 apis for persistence data (this is in my case, maybe in other cases would be necessary to use html5 apis like localstorage and other stuff).
An alternative to services is to use the value store.
In the base of my app I added this
var agentApp = angular.module('rbAgent', ['ui.router', 'rbApp.tryGoal', 'rbApp.tryGoal.service', 'ui.bootstrap']);
agentApp.value('agentMemory',
{
contextId: '',
sessionId: ''
}
);
...
And then in my controller I just reference the value store. I don't think it holds thing if the user closes the browser.
angular.module('rbAgent')
.controller('AgentGoalListController', ['agentMemory', '$scope', '$rootScope', 'config', '$state', function(agentMemory, $scope, $rootScope, config, $state){
$scope.config = config;
$scope.contextId = agentMemory.contextId;
...
Solution that will work for multiple scopes and multiple variables within those scopes
This service was based off of Anton's answer, but is more extensible and will work across multiple scopes and allows the selection of multiple scope variables in the same scope. It uses the route path to index each scope, and then the scope variable names to index one level deeper.
Create service with this code:
angular.module('restoreScope', []).factory('restoreScope', ['$rootScope', '$route', function ($rootScope, $route) {
var getOrRegisterScopeVariable = function (scope, name, defaultValue, storedScope) {
if (storedScope[name] == null) {
storedScope[name] = defaultValue;
}
scope[name] = storedScope[name];
}
var service = {
GetOrRegisterScopeVariables: function (names, defaultValues) {
var scope = $route.current.locals.$scope;
var storedBaseScope = angular.fromJson(sessionStorage.restoreScope);
if (storedBaseScope == null) {
storedBaseScope = {};
}
// stored scope is indexed by route name
var storedScope = storedBaseScope[$route.current.$$route.originalPath];
if (storedScope == null) {
storedScope = {};
}
if (typeof names === "string") {
getOrRegisterScopeVariable(scope, names, defaultValues, storedScope);
} else if (Array.isArray(names)) {
angular.forEach(names, function (name, i) {
getOrRegisterScopeVariable(scope, name, defaultValues[i], storedScope);
});
} else {
console.error("First argument to GetOrRegisterScopeVariables is not a string or array");
}
// save stored scope back off
storedBaseScope[$route.current.$$route.originalPath] = storedScope;
sessionStorage.restoreScope = angular.toJson(storedBaseScope);
},
SaveState: function () {
// get current scope
var scope = $route.current.locals.$scope;
var storedBaseScope = angular.fromJson(sessionStorage.restoreScope);
// save off scope based on registered indexes
angular.forEach(storedBaseScope[$route.current.$$route.originalPath], function (item, i) {
storedBaseScope[$route.current.$$route.originalPath][i] = scope[i];
});
sessionStorage.restoreScope = angular.toJson(storedBaseScope);
}
}
$rootScope.$on("savestate", service.SaveState);
return service;
}]);
Add this code to your run function in your app module:
$rootScope.$on('$locationChangeStart', function (event, next, current) {
$rootScope.$broadcast('savestate');
});
window.onbeforeunload = function (event) {
$rootScope.$broadcast('savestate');
};
Inject the restoreScope service into your controller (example below):
function My1Ctrl($scope, restoreScope) {
restoreScope.GetOrRegisterScopeVariables([
// scope variable name(s)
'user',
'anotherUser'
],[
// default value(s)
{ name: 'user name', email: 'user#website.com' },
{ name: 'another user name', email: 'anotherUser#website.com' }
]);
}
The above example will initialize $scope.user to the stored value, otherwise will default to the provided value and save that off. If the page is closed, refreshed, or the route is changed, the current values of all registered scope variables will be saved off, and will be restored the next time the route/page is visited.
You can use $locationChangeStart event to store the previous value in $rootScope or in a service. When you come back, just initialize all previously stored values. Here is a quick demo using $rootScope.
var app = angular.module("myApp", ["ngRoute"]);
app.controller("tab1Ctrl", function($scope, $rootScope) {
if ($rootScope.savedScopes) {
for (key in $rootScope.savedScopes) {
$scope[key] = $rootScope.savedScopes[key];
}
}
$scope.$on('$locationChangeStart', function(event, next, current) {
$rootScope.savedScopes = {
name: $scope.name,
age: $scope.age
};
});
});
app.controller("tab2Ctrl", function($scope) {
$scope.language = "English";
});
app.config(function($routeProvider) {
$routeProvider
.when("/", {
template: "<h2>Tab1 content</h2>Name: <input ng-model='name'/><br/><br/>Age: <input type='number' ng-model='age' /><h4 style='color: red'>Fill the details and click on Tab2</h4>",
controller: "tab1Ctrl"
})
.when("/tab2", {
template: "<h2>Tab2 content</h2> My language: {{language}}<h4 style='color: red'>Now go back to Tab1</h4>",
controller: "tab2Ctrl"
});
});
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular-route.js"></script>
<body ng-app="myApp">
Tab1
Tab2
<div ng-view></div>
</body>
</html>

Categories