I have a side menu and its controller. In another controller I get the user data and want to update my menu items. How to achieve that ? I tried using $watch and services but to no success. Also I never used $rootScope so please avoid if it is not the only solution.
.controller('menuCtrl', function($scope) {
$scope.username = ""
})
.controller('afterloginCtrl', function($scope) {
var a = "this is username"
$scope.username = a // here I wish to update username in menuCtrl
})
Please let me if you need more code or details.
EDIT
Actually I update user info via database table, from their I am retrieving the username and other info. So menu controller needs to update with current values in database every time
You can to use some service for sharing data between controllers.
For example:
.service('currentUser', () => ({data: {}, someMethod: () => {}}))
.controller('Ctrl1', (currentUser, $scope) => {$scope.user = currentUser.data;})
.controller('Ctrl2', (currentUser) => {currentUser.data.name = 'username';});
Obviously, you can also extend your service with some appropriate methods. etc.
Then you can use these methods:
.controller('Ctrl2', (currentUser, api) => {
api.retrieveUser()
.then(user => currentUser.setData(user));
});
.service('loginuser', () => ({}))
.controller('fistCtrl', (currentUser, $scope) => {
$scope.data1 = loginuser;
})
.controller('secondectrl', (loginuser) => {
loginuser.name = 'sessionname';
})
If you are using service or factory data will be lost after page refresh.
You Can use browser session storage.
sessionStorage.setItem('NAME', "XYZ"); //set Data
sessionStorage.getItem('NAME'); // Get Data
//Afetr use you can clear data.
sessionStorage.clear();
You can use localStorage
Use the following code in your first controller:
localStorage.setItem($scope.username);
and the next controller:
$scope.username = localStorage.getItem();
As per the above comments your requirement is to persistent the username if user closes app and reopens.So, by using service or factory data will be lost once app reload or close.
Work around :
You can use localStorage to store username and can also access the data across controllers.
Code :
You can create a common factory service that will save and return the saved local storage data based on the key.
app.factory('storageService', ['$rootScope', function($rootScope) {
return {
get: function(key) {
return localStorage.getItem(key);
},
set: function(key, data) {
localStorage.setItem(key, data);
}
};
}]);
In controller :
Inject the storageService dependency in the controller to set and get the data from the local storage.
.controller('menuCtrl', ['$scope','storageService',function($scope,storageService) {
// Get local storage data from storageService
storageService.get('username');
}])
.controller('afterloginCtrl',['$scope','storageService',function($scope,storageService) {
var a = "this is username"
// Set local storage data to storageService
storageService.set('username', a);
}])
Related
How can we broadcast updated data from factory.
Am having two factories and two controllers.
Service1: updates the data into db
app.factory('uac',function($http,$q, $cookies)
{
formData.uClient = function(data)
{
var client = $http.post('add_client/',data)
return $q.all({'response':client})
}
}
service 2: gets list of clients from db
app.factory('adService',function($http, $q)
{
clientData = {}
clientData.getListofClients = function()
{
var listOfClients = $http.get('get_clients/')
return $q.all({'listOfClients':listOfClients})
}
return clientData
})
controller 1: sends data to be updated to service
app.controller('acController', function($scope,uac)
{
$scope.clientDatadata = {name:"abcd"}
uac.uClient($scope.clientData)
}
controller 2: gets clients data from service
app.controller('getDetailsController',function($scope,adService)
{
adService.getListofClients().then(function(data)
{
$scope.clientList = data.listOfClients.data
console.log($scope.clientList)
},
function(error)
{
console.log("Can fetch data")
});
}
First I will call getDetailsController to get all clients and whenever a new client is added by calling "acController" i want the updated list of clients in "$scope.clientList".How can i get it done?
You can $emit on event from the sender controller and listen for it in the receiver controller. Since I'm not sure about the hierarchy of your controllers, I'll listen on $rootScope:
controller 1: sends data to be updated to service
app.controller('acController', function($scope,uac)
{
$scope.clientDatadata = {name:"abcd"}
uac.uClient($scope.clientData).then(function(res){
$scope.$emit('serviceUpdated', res); // you can send data if you wish
});
}
controller 2: gets clients data from service
app.controller('getDetailsController',function($scope,adService,$rootScope)
{
function getList(){
adService.getListofClients().then(function(data)
{
$scope.clientList = data.listOfClients.data
console.log($scope.clientList)
},
function(error)
{
console.log("Can fetch data")
});
}
getList();
$rootScope.$on('serviceUpdated', getList);
}
There are three ways to go for this:
(easy) Create a factory which will contain the list of clients and use it directly on your view.
-
myApp.factory('clientList', function () {
return [];
});
call controller 2 to get the list of clients and save on the factory:
app.controller('getDetailsController',function($scope,adService, clientList)
{
adService.getListofClients().then(function(data)
{
clientList = data;
},
function(error)
{
console.log("Can fetch data");
});
}
controller 1: sends data to be updated to service and saves the returned data on the clientList factory
app.controller('acController', function($scope,uac, clientList)
{
$scope.clientDatadata = {name:"abcd"};
clientList = uac.uClient($scope.clientData);
}
The issue about this solution is that in a complex app you wouldn't want to have the data exposed via a factory.
Implement getters and setters on the factory so you don't expose the data to the views but rather have them controlled by the controllers (using $watch).
Use $emit as explained on the answer by #Shomz. But, I would propose to make another get list request after the emission is received. I'd rather broadcast the updated data(in this case the response of the post/update request) and than update the variables that are bound to views.
So this is my service that I use to fetch user details.
angular.module('app')
.factory('userDetailService', function($http) {
var userData = {};
function getUserDetails(userId) {
if (userId) {
return $http.get("/users/" + userId).success(function(data) {
angular.copy(data[0], userData);
});
}
}
return {
userData: userData,
getUserDetails: getUserDetails
}
})
Now in Controller 1 that uses this service, I have this bit of code which works fine as I get the relevant data.
$scope.getUserId = function(userId) {
if (userId) {
$scope.userData = userDetailService.userData;
userDetailService.getUserDetails(userId).success(function() {
console.log($scope.userData); //Prints valid user data
});
}
};
After this function executes in Controller 1, I try to do the following in Controller 2:
$scope.userData = userDetailService.userData;
console.log($scope.userData); //Prints null
But $scope.userData is null. Isn't the whole purpose of using a service to share data between controllers? Since I have already set the value of userData in Controller 1, shouldn't I be able to access it in Controller 2?
Weirdly enough, the modal dialog which is the template for Controller 2 is able to access data in the form of {{userData.first_name}} or {{userData.last_name}}. If this works, why is $scope.userData null? What am I missing?
Edit:
Template 1:
<div id="myModal" ng-controller="Controller 1">
<modal-configure-user></modal-configure-user>
<a data-toggle="modal" data-target="#configureUserModal" href="#" ng-click="getUserId(user.id)" data-id="user.id">{{user.first_name + ' ' +user.last_name}}</a>
</div>
Template 2:
<div ng-controller="Controller 2" id="configureUserModal">
</div>
Both are modal dialog windows.
Your approach is not very reliable, since you can't be 100% sure that data has already loaded when you try to access it in the second controller. Instead of assigning user data to variable always invoke getUserDetails method, which returns a promise. Then you just need to cache loaded data to avoid duplicated requests.
angular.module('app')
.factory('userDetailService', function($q, $http) {
var userData;
function getUserDetails(userId) {
if (userId) {
return userData ? $q.when(userData) : $http.get("/users/" + userId).success(function(data) {
userData = data;
return userData;
});
}
}
return {
getUserDetails: getUserDetails
}
});
Wrapping userData into $q.when creates a promise object, which resolves immediately. This is what you need, because service API is now consistent - you always deal with promises.
The usage in both controller then would be:
userDetailService.getUserDetails(userId).then(function(data) {
$scope.userData = data;
});
I am very new with AngularJS. Thank you for answer. My code is as follow:
mainModule.controller('MainController', function($scope, $http) {
$http.get('http://localhost/backend/WebService.php', {params: {entity: 'IndexPageEntity'}}).
success(function(data) {
$scope.intro = data[0].IndexPageContent;
});
$http.get('http://localhost/backend/WebService.php', {params: {entity: 'ExhibitionServiceEntity'}}).
success(function(data) {
$scope.exhibit = data[0].ExhibitionServiceContent;
});
$http.get('http://localhost/backend/WebService.php', {params: {entity: 'ShootingServiceEntity'}}).
success(function(data) {
$scope.shooting = data[0].ShootingServiceContent;
});
});
My html file would be:
<div ng-controller="MainController">
<div>{{intro}}</div>
<div>{{exhibit}}</div>
<div>{{shooting}}</div>
</div>
I believe there must be some ways to improve the above code in order to reduce repetition. What I want is to pass entity parameter to the controller on creation.
Using ng-init to pass parameter is discouraged, according to the documentation. Writing custom directive to pass argument to scope does not work since parameters would be overwrittern.
What is the best practice to set params dynamically for use in $http? Thank you.
You should move all the logic to a service and use a directive. I would suggest you to modify your backend to return the same structured data, instead of IndexPageContent, ExhibitionServiceContent, etc. it should be Content or whatever name you want to use. But for now I've added a replace function to get the name of the content from the name of the entity.
mainModule.factory('webService', function($http) {
var apiUrl = 'http://localhost/backend/WebService.php';
function getContent(params) {
var config = {
'params': params
};
return $http.get(apiUrl, config);
};
return {
getContent: function(params) {
return getContent(params)
}
};
});
mainModule.controller('MainController', function($scope, webService) {
var params = {
'entity': $scope.entity
};
var contentName = $scope.entity.replace('Entity', 'Content');
webService.getContent(params).then(function (data) {
$scope.content = data[0][contentName];
});
});
mainModule.directive('EntityContent', function() {
return {
controller: 'MainController',
replace: true,
restrict: 'E',
scope: {
entity: '#entity'
},
template: '<div>{{ content }}</div>'
};
});
<div>
<entity-content entity="IndexPageEntity">
<entity-content entity="ExhibitionServiceEntity">
<entity-content entity="ShootingServiceEntity">
</div>
Create an object data and send the value for the key inside the object at every call.. Also pass the value for key to be set inside the scope..
E.g.
$scope.makeHttpCall = function(data) {
$http.get('http://localhost/backend/WebService.php', {params: data}).
success(function(data) {
$scope[$scope.key] = data[0][$scope.key];
});
};
you can then call this function as
$scope.key = 'IndexPageContent';
data = {
entity : 'yourValueHere'
};
$scope.makeHttpCall(data);
You can set other values as well inside the scope that are dynamic for each request..
I hope this makes sense to you...
I'm using AngularJS to login a user (using Restangular). The login controller gets returned a 'Token' which I then need to use on every request thereafter.
My question is, what is the best way to store this Token using AngularJS? It needs to exist for the lifetime of the app.
I was looking at services but I have to keep injecting it into the controllers on to keep it alive.
lifetime is not promise as far as you are using web apps, but if you want you can use localstorage,
here is an example service how to use localstorage in angular, you can add it to service.js file:
var storeService = innovidServices.factory('storeService', function() {
var service =
{
setClientData:function(client_details)
{
window.localStorage.setItem( "client_data", JSON.stringify(client_details) );
client_data = client_details;
},
getClientData:function()
{
if (client_data == null)
{
client_data = JSON.parse(window.localStorage.getItem("client_data"));
}
return client_data;
}
}
var client_data = null;
return service;
});
I think the best way is store this 'Token' in the $rootScope.
myapp.controller('loginCtrl', function($scope, $rootScope) {
...
$rootScope.token = Token;
...
});
Then use http interceptor to inject this as for example GET parameter to every query
myapp.factory('httpTokenInterceptor', function ($rootScope) {
return {
request: function (config) {
var token = $rootScope.token;
if (token) {
config.url = URI(config.url).addSearch({'token':token}).toString();
}
return config;
}
};
});
myapp.config(function ($httpProvider) {
$httpProvider.interceptors.push('httpTokenInterceptor');
});
Maybe I'm going about this the wrong way, i'm not sure, but I have 2 services, one is a user service which gets a bunch of details about the user from the server, the other being one that relies on some user details from the user service and then makes some more calls to the server to get other information.
Anyway, because of the async stuff that goes on when the 2nd service makes the calls the information required from the user server has not yet been populated.
I know Angular services can depend on one another, but not in this context it would appear?
factory('User', ['$resource', function ($resource) {
return $resource(usersUrl, {}, {
//The data model is loaded via a GET request to the app
query: {method: 'GET', params: {}, isArray: false},
putupdate: {method: 'PUT', params:{}}
});
}])
.factory('UserData', function() {
var data = {}
data.userinfo = {};
if(data = {}){
}
return {
updateinfo: function(newdata) {
data.userinfo = newdata;
// alert(data.userinfo.user)
},
userinfo: data
}
})
.factory('PlansData', ['UserData', 'User', '$rootScope', function(userData, user, $rootScope) {
var data = {}
data.plansinfo = {};
//alert(userData.data.userinfo.user.email)
if(data = {}){
}
return {
updateinfo: function(newdata) {
alert(user.query())
data.plansinfo = newdata;
},
plansinfo: data
}
}])
So I have a user service and a caching userdata service, but if I ever try and call anything from UserData in the PlansData service I get undefined.
How do I get plansData to wait for UserData to have some data?
Thanks
Tom
I'm not sure what you're trying to accomplish, but this line of code:
if(data = {}){
}
In both your services is wiping out your data object. You're setting the whole data object to be {}