Value of variable becomes undefined after calling data service - angularjs

I have a angular js controller 'TakeSurveyController' which calls a data service 'takeSurveyDataService'. The controller has a variable empId which I am accessing successfully using the 'this' keyword. However, the value of this variable becomes undefined soon after I make a call to the data service.
(function(){
dataUrls = {
employeeUrl : '/SurveyPortal/Company/Employees/'
}
angular.module('takeSurvey',[])
.service('takeSurveyDataService',function($http,$log){
this.checkEmployee = function(employeeId){
var url = dataUrls.employeeUrl + employeeId;
return $http.get(url);
};
})
.controller('TakeSurveyController',function($http,takeSurveyDataService,$location){
this.empId = '';
this.checkEmployee = function(){
takeSurveyDataService.checkEmployee(this.empId).then(this.attemptSurvey);//empId has value here. Call successful to data service
};
this.attemptSurvey = function(employeeResponse) {
if(employeeResponse.data=="true"){
$location.path('/attemptSurvey/'+this.empId); //empId variable undefined here, unable to access value that was available above
}
else{
this.empId = '';
alert("This empId has not been registered. Please register before taking survey!");
}
};
})
})();
Following is the html code.
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<div align="center" style="margin-top:50px">
<form name="checkEmployee" ng-controller="TakeSurveyController as takeSurveyController" ng-submit="takeSurveyController.checkEmployee()" >
<input type="text" ng-model="takeSurveyController.empId" placeholder="Employee ID" /><br>
<input type="submit" class="btn btn-large btn-success" value="Move to survey" />
</form>
</div>
</body>
</html>

You must be very carefull using this inside functions since 'this' words get different meaning each time depending on context. I believe during promise callback 'this' get's different meaning and it is loosing connection with TakeSurveyController. Please try to assign 'this' to 'self' variable which is always good practice in angular and js:
(function(){
dataUrls = {
employeeUrl : '/SurveyPortal/Company/Employees/'
}
angular.module('takeSurvey',[])
.service('takeSurveyDataService',function($http,$log){
var self = this;
self.checkEmployee = function(employeeId){
var url = dataUrls.employeeUrl + employeeId;
return $http.get(url);
};
})
.controller('TakeSurveyController',function($http,takeSurveyDataService,$location){
var self = this;
self.empId = '';
self.checkEmployee = function(){
takeSurveyDataService.checkEmployee(self.empId).then(self.attemptSurvey);//empId has value here. Call successful to data service
};
self.attemptSurvey = function(employeeResponse) {
if(employeeResponse.data=="true"){
$location.path('/attemptSurvey/'+self.empId); //empId variable undefined here, unable to access value that was available above
}
else{
self.empId = '';
alert("This empId has not been registered. Please register before taking survey!");
}
};
})
})();

Related

Angularjs scope data inside the function

I am trying to display the data to my view but $scope.plan outputs {}. I am thinking that it would output the fetched data from the initGetEdit function, console.log() inside the $http.post outputs expected data.
controller.js
var id = $stateParams.id;
$scope.plan = {}
$scope.initGetEdit = function(){
var data = { id : id }
$http.post("someUrl", data).then(function(res){
$scope.plan = res.data;
console.log($scope.plan); //----> logs expected data
})
}
$scope.initGetEdit();
console.log($scope.plan); //----> logs {}
In my view I have something like this.
view
<input ng-model="plan.something" type="text" />
UPDATE
First thank you for those answers provided and the comments, appreciated it. It gives me an insight. I solved my issue by removing the initGetEdit function and staying with just the http.post.
Try keeping the second console in watch.
$scope.$watch('plan',function(){
console.log($scope.plan);
});
At first, you declare a variable $scope.plan = {} after that in http call of your $scope.initGetEdit function its empty object after the function http is an async call your object may be filled based on the response. until that it will be an empty object.
#Ujjwala Bollam mention in answer to print it in the console.
var app = angular.module('testApp',[]);
app.controller('testCtrl',function($scope,$http){
//var id = $stateParams.id;
var id=1;
$scope.plan = {}
$scope.initGetEdit = function(){
var data = { id : id }
//$http.post("http://someurl", data).then(function(res){
$scope.plan ={id:1,something:"hai this is response data"};
console.log($scope.plan); //----> logs expected data
//})
}
$scope.initGetEdit();
console.log($scope.plan); //----> logs {}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div ng-app="testApp" ng-controller="testCtrl">
<input ng-model="plan.something" type="text" />
</div>

Updating HTML in Angular is not working

I am still learning angular and in my example projekt I have a problem on updating the view.
Got this in my header ....
<meta charset="UTF-8">
<title>{{ name }}</title>
And this in my body:
<body ng-controller="BodyController as body">
<input type="button" ng-click="changeTitle()" name="changeNameButton" value="change name"/>
This is my head controller:
myApp.controller('HeadController',
['$scope', 'ApplicationService', 'DataService', 'UserService', function ($scope, ApplicationService, DataService, UserService) {
var self = this;
$scope.name = ApplicationService.getTitle();
}]
);
And here is my body controller:
myApp.controller('BodyController', ['$scope', 'ApplicationService', function ($scope, ApplicationService) {
$scope.text = 'Hello, Angular fanatic.';
$scope.changeTitle = function () {
console.log('change the title');
ApplicationService.setTitle('test');
}
}]);
This is my application service
myApp.service('ApplicationService', ['ConfigurationService', function(ConfigurationService){
this.title = '';
this.setTitle = function (newTitle) {
console.log('new title (setter): ' + this.title);
this.title = newTitle
}
this.getTitle = function () {
if(this.title==''){
this.title = ConfigurationService.title + ' | ' + ConfigurationService.subtitle;
}
console.log('new title (getter): ' + this.title);
return this.title;
}
}]);
So far so good and sorry that I do not use codepen, etc. But it was not working in it, ...
My Problem: It is setting the title on initial load of the website, but not on pressing the button. The new name is set to ApplicationService.title, but header controller does not update it. Whats is wrong in this case? How can I update the title in the view...?
Regards
n00n
see the codepen for it: https://codepen.io/n00n/pen/bqaGKY
What you're doing is the equivalent of the following simple code:
//in the header controller
var name = service.getTitle();
// in the header template
display(name);
// later, in the body
service.setTitle('test');
// in the header template
display(name);
You see that this can't work: the variable name in the header controller has been initialized when the controller was created, and assigning a new value to the title stored in the service can't magically change the value of the name variable in the header controller. What you want is to display the title in the service:
<title>{{ getTitle() }}</title>
$scope.getTitle = function() {
return ApplicationService.getTitle();
};
That didn't work because you're calling getTitle method when title wasn't set. So that's it is referring to older title('undefined'). You can change your binding to
$scope.getTitle = ApplicationService.getTitle;
And then change HTML to
{{getTitle()}}
So title will get fetch from service and updated on the page on each digest cycle.
Other thing which I'd like to mention is, don't use(mix) $scope when you are using controllerAs, so then remove $scope from controller and bind data to below
var vm = this;
vm.getTitle = ApplicationService.getTitle;

multi data from different schema, angular display

I have a really long json that each comes from different schema.
I did push in order to get them all in one json - that works.
know I want to use a controller for all of them and display it to the screen.
my index
<!DOCTYPE html>
<html ng-app="showFrozen">
<head>
<title>frozen</title>
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap-theme.min.css">
</head>
<body ng-controller="showFrozenCtrl">
<tbody>
<div ng-repeat="themes in showFrozenController.themes" ng-show="$first">
<h2>{{themes.theme}}</h2>
<span>for age: </span>
<p>{{themes.age}}</p>
<span>description: </span>
<p>{{themes.description}}</p>
<p>{{themes.description_more}}</p>
<img ng-src="{{themes.image}}" width="170" height="170">
</div>
</table>
<script src="js/lib/angular/angular.min.js"></script>
<script src="js/showFrozenController.js"></script>
</body>
</html>
my controller
var showFrozen = angular.module('showFrozen',[]);
showFrozen.filter("allItems", function() {
return function(frozen) {
var resultArr = [];
angular.forEach(frozen,function(item) {
resultArr.push(item);
});
return resultArr;
};
});
var model = {};
showFrozen.run(function($http) {
$http.get("http://localhost:3000/frozen").success(function(data){
console.log(data);
model.frozen = data;
});
});
showFrozen.controller('showFrozenCtrl',function($scope) {
$scope.showFrozenController = model;
});
so I don't get any output - but I see the json in the console, I'm attaching an image.
In your controller model is undefined.
Move the HTTP call to your controller and in the success assign the scope.showFrozenController to data
You need to make your $http request inside of your controller.
showFrozen.controller('showFrozenCtrl',function($scope, $http) {
$http.get("http://localhost:3000/frozen").success(function(data){
console.log(data);
$scope.model = data;
});
});
This is because when you try and print items out in your template (html) what is actually being accessed inside of any {{ }} blocks is your $scope object. So to make data available to your template you must store it on your $scope.
Have a read of this blog post
showFrozen.factory('frozenDataSrv',function($http) {
return {
getFrozenData: getFrozenData
};
function getFrozenData() {
return $http.get("http://localhost:3000/frozen")
.then(getFrozenDataComplete)
.catch(getFrozenDataFailed);
function getFrozenDataComplete(response) {
return response.data.results;
}
function getFrozenDataFailed(error) {
logger.error('XHR Failed for getFrozenData.' + error.data);
}
}
});
showFrozen.controller('showFrozenCtrl',function($scope, frozenDataSrv) {
frozenDataSrv.getFrozenData()
.then(function(response){
console.log(response)
})
});

After make ajax-post request the html elements are not refresh in angular

I have a issue.i make ajax-post request then it execute properly then i get the response.After process the response i need again make ajax-get then those data i set to a variables in the scope.the data are successfully assign in to variable but html elements are not refresh.this is the sample code.
this is html part
<div ng-controller="AppManagerCtrl" >
<md-list-item ng-repeat="app in apps">
<div>
<div flex="20" layout-padding>
<p>{{app.appId}}</p>
</div>
<div flex="20" layout-padding>
<p>{{app.appName}}</p>
</div>
</md-list-item>
</div>
this the angular service
app.service('AppManagerService',function($http){
this.loadApps = function(){
var request = $http.get('apps');
return request.then(handleSuccess,handleError);
};
this.submitApp = function(){
var request = $http.post('apps',
$('#newAppDetail').serialize(),
{headers: {'Content-Type': 'application/x-www-form-urlencoded'}}
);
return request;
};
function handleError(responce){
console.log(responce);
}
function handleSuccess( response ) {
return response.data.value;
}
});
this the angular controller
app.controller('AppManagerCtrl', function($scope,$mdDialog,$mdMedia,AppManagerService) {
function loadApps(){
AppManagerService.loadApps().then(function(apps){
$scope.apps = apps;
console.log($scope.apps);
}
);
}
loadApps();
$scope.submitNewApp = function(){
AppManagerService.submitApp().then(function(responce){
var data = responce.data;
if(data.status == 1){
loadApps();
}
});
};
});
all these are in the html body.from the begin html part then angular service and finally controller.
The result of an ajax call isn't monitored by Angular, which is why your scope isn't updated (it will be on the digest though).
To solve this, you must manually call $scope.apply().
However, if another digest is already in progress, it will throw an error. So it's safer to use the $timeout utility:
function loadApps(){
AppManagerService.loadApps().then(function(apps){
$timeout(function() {
// update your scope variables here. The refresh will occur automatically.
$scope.apps = apps;
console.log($scope.apps);
});
});
}

why factory don't work properly between the directives?

I make two directives .To communicate between two directives I used a factory .
but it not work properly ..I want to delete my text when I press delete button ..I take factory to do my task but it not working .I also try to take service .it also don't help
here is my code
http://plnkr.co/edit/Yenmira9J9XpjscQzRoX?p=preview
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
</head>
<body ng-app="app">
<a></a>
<b></b>
<script>
angular.module('app',[]).directive('a',function(){
return {
restrict :'E',
scope:{},
templateUrl:'a.html',
controller:'ts',
controllerAs:'vm'
}
}).controller('ts',function(sharedService){
var vm=this;
vm.delete=function(){
alert('--');
sharedService.deletepro();
}
}).directive('b',function(){
return {
restrict :'E',
scope:{},
templateUrl:'b.html',
controller:'bb',
controllerAs:'vm'
}
}).controller('bb',function(sharedService){
var pm=this;
pm.message= sharedService.sendData();
}).factory('sharedService', function() {
var data = {};
function deletepro(){
data = {};
}
function sendData(){
var obj = {name:"pQr"};
data = obj;
return data;
}
return {
sendData: sendData,
deletepro: deletepro
};
});
</script>
</body>
</html>
After your controller is first initialized, data and vm.message reference the same object, but when you run deletepro then data references a new object, but vm.message still references the old one.
If you want to pass data in this way, you must never replace data with a new object (otherwise, controllers will have to get the new object again).
Instead of data = {};, try data.name = '';
It looks like you're expecting that it will update because data is a shared reference. But you are resetting it to {}, which breaks the reference. You instead need to modify it:
function deletepro(){
for(var prop in data){
delete data[prop];
}
}
Also, keep in mind a and b are both real html tags, not sure if there are any issues ovewriting the standard ,

Resources