i can't find a solution to this, basicly everytime i do a login, i want to store the user that i get from the node end point in the service, after that in my main Controller i should get the name of the user, but that never happen, dunno why
here is the code:
app.controller('MainCtrl', function ($scope, $state,$location,$http,user) {
$scope.user = {
nome: user.getProperty()
};
$scope.showRegister = function () {
$state.go('register');
}
$scope.showLogin = function () {
$state.go('login');
}
});
app.controller('loginController', function ($scope, $http, $state,user) {
$scope.login = function () {
var data = {};
data.password = $scope.loja.password;
data.email = $scope.loja.email;
$http.post('http://localhost:8080/login/',data)
.success(function (data) {
console.log(data);
user.setProperty(data.nome);
$state.go('home');
})
.error(function (statusText) {
console.log("failed");
});
}
});
user service
app.service('user', function () {
var property = {};
return {
getProperty: function () {
return property.nome;
},
setProperty: function (value) {
property.nome = value;
}
};
});
You could just watch your service for changes by adding this code to your MainCtrl:
$scope.$watch(function () { return user.getProperty();}, updateProp, true);
function updateProp(newValue, oldValue) {
$scope.user = {
nome: newValue
};
}
updateProp gets executed everytime the value of user.getProperty() changes.
Your main issue is with your MainCtrl . In the initial execution of MainCtrl there is no value set into your service so its get blank. MainCtrl executes before setting the value in the service.
$scope.user = {
nome: user.getProperty()
};
this code should be executed after setting the value in the service but it executes in the initialization of controller.
You can get the reference from the fiddle below.
http://jsfiddle.net/ADukg/9799/
Related
In angularJS, With one call, when get the service response need access that json value in multiple controllers but in same page
I have two controller js file and both controllers are called in the same page when I called the service "this.getNavigationMenuDetails" in the first controller.js and as well as called in the controller2.js file as well. without timeout function, I want to access that same response which I get it from the "this.getNavigationMenuDetails" service in controller2.js. But it happened that service call twice in the page. I don't want to call the same service twice in a page.
When js are loading that time both controllers are called in the same layer then getting the response from the service so on the second controller2.js file code is not execute after the response. How can I solve this issue so that only one call i can get the response and access this response in controller2.js also.
controler1.js
var app = angular.module("navApp", []);
app.controller("navCtrl", ['$scope', 'topNavService', '$window', function ($scope, $timeout, topNavService, $window) {
$scope.menuItemInfo = {};
/*Navigation Menu new Code */
$scope.getNavigationDetails = function () {
topNavService.getNavigationMenuDetails().then(function (result) {
$scope.menuItemInfo = result;
angular.forEach($scope.menuItemInfo.items, function (val, key) {
if (val.menuTitle ===
$window.sessionStorage.getItem('selectedNavMenu')) {
if ($scope.menuItemInfo.items[key].isEnabled) {
$scope.menuItemInfo.items[key].isActive = 'highlighted';
} else {
$window.sessionStorage.removeItem('selectedNavMenu');
}
}
if (val.menuTitle === 'Find a Fair' && !val.hasSubMenu) {
$scope.menuItemInfo.items[key].redirectTo = appConfig.findafairpageurl;
}
});
});
};
$scope.init = function () {
if ($window.location.pathname.indexOf('all-my-fairs.html') > 0) {
if (angular.isDefined($cookies.get('cpt_bookfair'))) {
$cookies.remove('cpt_bookfair', {
path: '/'
});
}
}
$scope.getNavigationDetails();
$scope.callOnLoad();
};
$scope.init();
}]);
app.service('topNavService', ['$http', '$timeout', '$q'function ($http, $timeout, $q) {
var menuInfo;
this.getNavigationMenuDetails = function () {
if (!menuInfo) {
// If menu is undefined or null populate it from the backend
return $http.get("/etc/designs/scholastic/bookfairs/jcr:content/page/header-ipar/header/c-bar.getMenuDetails.html?id=" + Math.random()).then(function (response) {
menuInfo = response.data;
return menuInfo;
});
} else {
// Otherwise return the cached version
return $q.when(menuInfo);
}
}
}]);
Controller2.js
var app = angular.module('bookResourcePage', []);
app.controller('bookResourceCtrl', ['topNavService', '$scope', function (topNavService, $scope) {
$scope.topInfo = '';
topNavService.getNavigationMenuDetails.then(function success() {
$scope.productId = $scope.topInfo.isLoggedin;
$scope.linkParam = '?productId=' + $scope.productId;
}, function failure() {
console.error("something bad happened");
});
}]);
The service would work better if it cached the HTTP promise instead of the value:
app.service('topNavService', function ($http) {
var menuInfoPromise;
this.getNavigationMenuDetails = function () {
if (!menuInfoPromise) {
// If menu is undefined or null populate it from the backend
menuInfoPromise = $http.get(url);
};
return menuInfoPromise;
};
});
The erroneous approach of caching the value introduces a race condition. If the second controller calls before the data arrives from the server, a service sends a second XHR for the data.
You can do this with following approach.
Service.js
app.service('topNavService', function($http) {
var menuInfoPromise;
var observerList = [];
var inProgress = false;
this.addObserver(callback) {
if (callback) observerList.push(callback);
}
this.notifyObserver() {
observerList.forEach(callback) {
callback();
}
}
this.getNavigationMenuDetails = function() {
if (!menuInfoPromise && !inProgress) {
inProgress = true;
// If menu is undefined or null populate it from the backend
menuInfoPromise = $http.get(url);
this.notifyObserver();
};
return menuInfoPromise;
};
});
You have to make a function in service to add your controller's function on list. then each controller will register their get function on service and call service method to get data. first call will make service variable inProgress to true. so it will prevent for multiple server request. then when data available to service then it will call its notifyObserver function to message for all controller by calling their function.
Controller 1
app.controller('ctrl1', ['service', '$scope', function(service, $scope) {
service.addObserver('getData1'); //name of your controller function
$scope.getData1() {
service.getNavigationMenuDetails.then(function success() {
$scope.productId = $scope.topInfo.isLoggedin;
$scope.linkParam = '?productId=' + $scope.productId;
}, function failure() {
console.error("something bad happened");
});
}
$scope.getData1()
}]);
Controller 2
app.controller('ctrl1', ['service', '$scope', function(service, $scope) {
service.addObserver('getData2'); //name of your controller function
$scope.getData2() {
service.getNavigationMenuDetails.then(function success() {
$scope.productId = $scope.topInfo.isLoggedin;
$scope.linkParam = '?productId=' + $scope.productId;
}, function failure() {
console.error("something bad happened");
});
}
$scope.getData2()
}]);
with this approach you can real time update data to different controllers without have multiple same request to server.
Problem: A controller variable vm.boatList (intended to be bound to a service variable, SearchService.boatList) is not updating with the service variable.
Code Snippets: Complete code at the bottom.
Controller
function SearchController($stateParams, SearchService) {
var vm = this;
vm.boatList = SearchService.boatList;
Service
function SearchService(BoatsDataService) {
var service = {
boatList: null,
getBoatList: getBoatList,
params: {}
};
return service;
Additional Data:
The getBoatList function called from the controller works - it logs data from the SearchService to the console. When I log vm.boatList immediately afterward, it's null.
Also, <div ng-repeat="boat in SearchController.boatList">...</div> only works when I assign directly to vm.boatList.
Console Output:
Array[3]
null
Complete Controller:
(function () {
'use strict';
angular.
module('trips').
controller('SearchController', SearchController);
SearchController.$inject = ['$stateParams', 'SearchService'];
function SearchController($stateParams, SearchService) {
var vm = this;
vm.boatList = SearchService.boatList;
vm.initialParams = getParams();
activate();
////////////////////
function activate() {
setInitialParams();
SearchService.getBoatList()
.then(function (data) {
SearchService.boatList = data;
console.log(SearchService.boatList); // Logs data.
console.log(vm.boatList); // Logs null.
})
.catch(function (error) {
console.log(error);
});
}
function getParams() {
var params = {
location: $stateParams.location,
passengers: $stateParams.passengers,
maxPrice: $stateParams.maxPrice,
minPrice: $stateParams.minPrice,
embark: $stateParams.embark,
disembark: $stateParams.disembark,
category: $stateParams.category
};
return params;
}
function setInitialParams() {
SearchService.params = getParams();
}
}
})();
Complete Service:
(function () {
'use strict';
angular.
module('trips').
factory('SearchService', SearchService);
SearchService.$inject = ['BoatsDataService'];
function SearchService(BoatsDataService) {
var service = {
boatList: null,
getBoatList: getBoatList,
params: {}
};
//$scope.$watch('service.params', function () {
// getBoatList().then(function (data {
// service.boatList = data;
// })
// }, true
//);
return service;
//////////////////////
function getBoatList() {
return BoatsDataService.BoatList
.query(service.params)
.$promise
}
}
})();
Recap: I don't know how to two-way bind, I guess.
When you're trying to bind a variable that's directly on the service, it will fail (see call by sharing). However, if you wrap it with an object, it will work like you expect, see this Fiddle.
So in your case, if you bind an object inside the service to your controller, it should be fine -
Service:
var service = {
boatListObj : {
boatList: null
},
getBoatList: getBoatList,
params: {}
};
Controller:
vm.boatListObj = SearchService.boatListObj;
Promise response:
.then(function (data) {
SearchService.boatListObj.boatList = data;
console.log(SearchService.boatListObj.boatList); // Logs data.
console.log(vm.boatListObj.boatList); // Should log fine now
})
The reason why <div ng-repeat="boat in SearchController.boatList">...</div> is not working is because SearchController.boatList is not on the $scope. It either must be on the $scope, or addressed via ControllerAs syntax when it's placed on the controller.
I am trying to push a new row of data to a table, after submitting the form. However, the table, which is called UrlListCtrl is different from the form, which is UrlFormCtrl.
function UrlFormCtrl($scope, $timeout, UrlService) {
$scope.message = '';
var token = '';
$scope.submitUrl = function(formUrls) {
console.log('Submitting url', formUrls);
if (formUrls !== undefined) {
UrlService.addUrl(formUrls).then(function(response){
$scope.message = 'Created!';
// I need to update the view from here
});
} else {
$scope.message = 'The fields were empty!';
}
}
In UrlFormCtrl, I am sending an array to the database to be stored, afterwards I'd like to update the view, where UrlListCtrl handles it.
function UrlListCtrl($scope, $timeout, UrlService){
UrlService.getUrls().then(function(response){
$scope.urls = response.data;
});
}
I am trying to push the new data to $scope.url. Here is the service:
function UrlService($http) {
return {
addUrl: addUrl,
getUrls: getUrls
}
function addUrl(formUrls) {
console.log('adding url...');
return $http.post('urls/create', {
original_url: formUrls.originalUrl,
redirect_url: formUrls.redirectUrl
});
}
function getUrls() {
return $http.get('urls/get');
}
}
I'm still trying to understand Angular, so this is pretty complicated for me. How can I update $scope.urls from within UrlFormCtrl?
I am not sure that I understand your question completely but I will try to answer it anyways =).
So you are trying to update a variable whose value was changed in another controller?
That is where service can be useful.
Here are the basic steps:
In the service, you have that variable:
myApp.service('ServiceName', ['$http', function(){
var urls = [];
return{
urls: urls
}
}])
Put $watch in one controller, where you want to get that new value:
myApp.controller('FirstController', function(...){
$scope.$watch(function () {
return ServiceName.urls;
}, function (newVal) {
$scope.urls = newVal;
});
})
Then, you change it from another controller:
myApp.controller('SecondController', function(...){
ServiceName.urls.push('newValue');
})
This should do it. $scope.urls will be updated in the first controller even if it was changed in the second.
The concept of $watch may be new to you. So it basically executes a callback function, whenever the first function returns a new value. That is, whenever the variable that is being watched changes.
In your case:
You will have a variable inside your service:
function UrlService($http) {
var urls = [];
function addUrl(formUrls) {
console.log('adding url...');
return $http.post('urls/create', {
original_url: formUrls.originalUrl,
redirect_url: formUrls.redirectUrl
});
}
function getUrls() {
return $http.get('urls/get');
}
return {
addUrl: addUrl,
getUrls: getUrls
urls: urls
}
}
Put a $watch inside UrlListCtrl:
function UrlListCtrl($scope, $timeout, UrlService){
$scope.$watch(function () {
return UrlService.urls;
}, function (newVal) {
$scope.urls = newVal;
});
}
Then, change the value of urls from UrlFormCtrl:
$scope.submitUrl = function(formUrls) {
if (formUrls !== undefined) {
UrlService.addUrl(formUrls).then(function(response){
$scope.message = 'Created!';
UrlService.urls = response['urls'];
});
} else {
$scope.message = 'The fields were empty!';
}
}
The $watch you put inside UrlListCtrl will insure that the new value will be assigned to $scope.urls inside UrlFormCtrl.
I am trying to create an Angular Factory, this is based on a example from a plural site course http://www.pluralsight.com/training/player?author=shawn-wildermuth&name=site-building-m7&mode=live&clip=3&course=site-building-bootstrap-angularjs-ef-azure.
From debugging the code in Chrome it appears to run fine. I can see when I debug it that the service gets my data and puts it in my array but when I look at the controller in either $scope.data or dataService.data the arrays are empty. I don't see any javascript errors. I'm not sure what I'm doing wrong, any suggestions. I'm using AngularJS v1.3.15.
module.factory("dataService", function($http,$routeParams,$q) {
var _data = [];
var _getData = function () {
var deferred = $q.defer();
$http.get("/api/v1/myAPI?mainType=" + $routeParams.mainType + "&subType=" + $routeParams.subType)
.then(function (result) {
angular.copy(result.data,_data);
deferred.resolve();
},
function () {
//Error
deferred.reject();
});
return deferred.promise;
};
return {
data: _data,
getData: _getData
};});
module.controller('dataController', ['$scope', '$http', '$routeParams', 'dataService',function ($scope, $http, $routeParams, dataService) {
$scope.data = dataService;
$scope.dataReturned = true;
$scope.isBusy = true;
dataService.getData().then(function () {
if (dataService.data == 0)
$scope.dataReturned = false;
},
function () {
//Error
alert("could not load data");
})
.then(function () {
$scope.isBusy = false;
})}]);
On
return {
data: _data,
getData: _getData
};});
you have "data: _data," while your array is named just "data". Change the name of the variable to match and it will work:
var _data = [];
Why would you use deferred from $q this way?
The proper way to use $q:
$http.get("/api/v1/myAPI?mainType=" + $routeParams.mainType + "&subType=" + $routeParams.subType)
.success(function (result) {
deferred.resolve(result);
}).error(
function () {
//Error
deferred.reject();
});
And then in controller
dataService
.getData()
.then(function success(result) {
$scope.data = result; //assing retrived data to scope variable
},
function error() {
//Error
alert("could not load data");
});
In fact, there are some errors in your codes :
In your Service, you define var data = [];, but you return data: _data,. So you should correct the defination to var _data = []
you don't define _bling, but you use angular.copy(result.data,_bling);
One more question, why do you assigne the service to $scope.data : $scope.data = dataService ?
EDIT :
Notice that there 3 changes in the following codes:
comment the $scope.data = dataService;, because it makes no sense, and I think that $scope.data should be the data that the service returns.
$scope.data = dataService.data;, as I described in 1st point. You can see the result from the console.
In the if condition, I think that you want to compare the length of the returned data array, but not the data.
module.controller('dataController', ['$scope', '$http', '$routeParams', 'dataService',function ($scope, $http, $routeParams, dataService) {
// $scope.data = dataService;
$scope.dataReturned = true;
$scope.isBusy = true;
dataService.getData().then(function () {
if (dataService.data.length === 0){
$scope.dataReturned = false;
}else{
$scope.data = dataService.data;
console.log($scope.data);
}
},
// other codes...
})}]);
I have this function triggered when I click a button.
.controller('Formctrl', function($scope, ichrisLayoutLeavebalanceService){
$scope.listRowSelected = function (list, item) {
var det = { detnumber: item.detnumber };
ichrisLayoutLeavebalanceService.callPost(det).success(function (data){ ichrisLayoutLeavebalanceService.leaveBalanceProcess(); });
};
});
However, it seems like I can't access the leaveBalanceProcess(). It seems like only the factory part is enabled to be shared. Here's my controller and factory code that is access by the code above.
.directive(/*code... code...*/{/*code... long code...*/
/*code... code...*/},
controller : ($scope, ichrisLayoutLeavebalanceService) {
function par(){
//code... code...
}
$scope.leaveBalanceProcess = function (){/*codes... codes... */}
$scope.build = function () {
ichrisLayoutLeavebalanceService.callPost(par()).success(function (data) { $scope.leaveBalanceProcess(data) });
}
$scope.build();
}
})
.factory('ichrisLayoutLeavebalanceService', ['$http', function ($http) {
var leaveBalanceService = {};
leaveBalanceService.callPost = function (par) {
return $http.post('/api/values/entries/LeaveBalanceEntries', par);
}
return leaveBalanceService;
}]);
So now how can I acces the whole controller?