How to declare a variable accessible to whole function in angularjs? - javascript

(function (angular) {
'use strict';
angular
.module('app')
.controller('ListSharedContentCtrl', ['$scope','$log','UserService', 'ContractService','ContentOwnerService','PlatformPartnerService',function ($scope, $log, userService, contractService,contentOwnerService,platformPartnerService) {
$scope.init = function () {
var contractIds =[];
var contentOwnerId;
var platformPartnerId;
var user=userService.getCurrentUser('true');
var contentOwner=userService.isCurrentUserIsContentOwner();
var platformPartner=userService.isCurrentUserIsPlatformPartner();
if(contentOwner == "true")
{
contentOwnerService.getContentOwnerId().then(function(savedContentOwnerId) {
contentOwnerId=savedContentOwnerId;
console.log(contentOwnerId);//here I can log the value
},function(error) {
$log.error("Error fetching contract id:" + error.message);
});
}
console.log(contentOwnerId); //but Here I cant log the value..Its showing undefined
} $scope.init();
}]);
})(angular);
Now my question is how to make the scope of the variable "contentOwnerId" available to whole function?Please anyone help me I cant figure it out..Thanks in advance..!

You are declaring contentOwnerId twice; once inside the if block, once outside it. The one outside is declared, but never assigned a value. It should be null where it is showing null.

The reason why you are getting the contentOwnerId undefined is that it is undefined until when the getcontentOwnerId() promise succeed!
if you do
var contentOwnerId = "before resolving the promise";
at the beginning of your init() you will probably have that string logged to console, instead of undefined

use $scope.contentOwnerId instead of var contentOwnerId.
See $scope.contentOwnerId is available to whole controller i.e ListSharedContentCtrl.
normal javascript variable are limited to functions where as $scope is available to entire CONTROLLER

The .then() method belongs to a promise.
This means it won't be executed immediately, but later in the angular life cycle.
Your console.log() will always log 'undefined' because your variable won't be initialized there.
You can try this to log the value:
$scope.$watch(
function() { return contentOwnerId; },
function(newContentOwnerId, oldContentOwnerId) {
console.log(newContentOwnerId);
}
);

Related

Put local variable in angular.forEach loop in the global

Hello I have created a variable inside the angular.forEach loop that I need outside the loop to bind to the $scope, but i donĀ“t know how to get outside this variable miAlumno.
Thanks.
'use strict';
angular.module('jarciaApp')
.controller('alumnoCtrl', function($routeParams, $firebaseArray) {
var ref = firebase.database().ref('PrimeroA');
var JarciaArray = $firebaseArray(ref);
var id = $routeParams.id;
var curso = $routeParams.curso;
var miAlumno;
JarciaArray.$loaded()
.then(function(miAlumno) {
angular.forEach(JarciaArray, function(alumno, miAlumno) {
if (alumno.Id == id) {
var miAlumno = alumno;
}
})
});
console.log(miAlumno);
});
Don't declare variable miAlumno in loop. Declare it outside and it will be visible.
Pay attention at that console.log(miAlumno), it probably will be always null because of the asynchronous assignement.
If I understand correctly, you are wanting to use the alumno variable you have passed into the function outside the scope of that function?
You can go about it by creating/declaring a global variable outside the function just as you did with miAlumno, then simply assign your global variable to the value your function produces. Also you have miAlumno declared twice, once outside as a global, then inside the for loop.
Apologies if I'm misunderstanding, and if so, please elaborate.
It sounds like you're using the ControllerAs syntax, which means what traditionally would be scope variables are automatically bound as properties of the controller. You can simply set the variable inside of the loop, using a cached value of this:
'use strict';
angular.module('jarciaApp')
.controller('alumnoCtrl', function($routeParams, $firebaseArray) {
var ref = firebase.database().ref('PrimeroA');
var JarciaArray = $firebaseArray(ref);
var id = $routeParams.id;
var curso = $routeParams.curso;
var me = this;
JarciaArray.$loaded()
.then(function() {
angular.forEach(JarciaArray, function(alumno) {
if (alumno.Id == id) {
me.miAlumno = alumno;
}
});
// This will work to show the value
console.log(me.miAlumno);
});
// This still won't work, since $loaded is asynchronous
console.log(this.miAlumno);
});
I've also removed the extra attempts to pass miAlumno to the then function and the callback for forEach; those are unnecessary.
Do note the comments about console.log. I believe the $loaded() is asynchronous; thus it will not be set until whatever process that is actually finishes. If you move the log to inside the then(), you'll see the result.

Updating a 'this' value in a service via a function

I'm quite new to Angular and am trying to understand how everything works. I've been poking around and couldn't find any information on how to do this. So, I've got a service that defines
this.totalCount = 0;
In my controller, my get request retrieves some emails and then executes a function called addMessage for each message it retrieves. The addMessage function is in my service.
The function in my service looks like this:
this.addMessage = function (messageObj) {
this.messagesList.push(messageObj);
}
Basically, I am trying to increment this.totalCount each time this function is executed so that it will update and then can be displayed in the view. I have it displaying in the view currently, however its number always remains 0.
I've tried the following:
1.
this.addMessage = function (messageObj) {
this.messagesList.push(messageObj);
this.totalCount++;
}
2.
var count = this.totalcount
this.addMessage = function (messageObj) {
this.messagesList.push(messageObj);
count++; //and then attempted to display this value in the view but with no luck
}
Any tips would be greatly appreciated.
try this:
var that = this;
this.addMessage = function (messageObj) {
that.messagesList.push(messageObj);
}
I assume that you're binding the var this way in your controller and your view
Service :
this.totalCount = 0;
this.totalCount++;
Controller :
$scope.totalCount = service.totalCount;
view :
{{totalCount}}
And if you're actually doing it like this, you should face this kind of trouble.
The main problem is that totalCount is a primitive var and doing this.totalCount++ will break the reference. If you want to keep some var you should bind it as a sub-object.
This way :
Service :
this.utils = {};
this.utils.totalCount = 0;
this.utils.totalCount++;
Controller :
//This is the most important part. You bind an object. Then even if you loose the totalCount reference, your object will keep its own reference.
$scope.myServiceUtils = service.utils;
View :
{{myServiceUtils.totalCount}}
Actually in service (it's a matter of taste) i prefer a lot to use the object syntax instead of this (as "this" can be confusing)
This way :
var service = {};
service.utils.totalCount = 0;
service.addItem = function(){
...
}
return service;
Hope that was your issue.
You pass argument to another function which has different scope than your service. It is trick with assigning current object to variable, which is visible from function.
var that = this;
this.addMessage = function (messageObj) {
that.messagesList.push(messageObj);
that.totalCount++;
}
Should work.
So you assign that variable with current object, which is visible in inner function scope.
In a function addMessage body, this refers to function scope which is new, and there is no compiler error, but messagesList is a null object and totalCount is incremented, but after program leave function, it's not visible in service, because it is in a function scope which isn't assigned to any variable.
To update service variable as it changes in your controller, use $watch.
$scope.$watch(function() {
return messagesService.totalCount;
}, function(new,old){
$scope.totalmessagecount = messagesService.totalCount;
});
First parameter of $watch if function which return observed for change element. Another is standard function to perform operation after update.

Angular.js: Why does mutating $scope with a simple helper function result in uninterpolated {{...}} expressions?

Alright, here's a git diff:
...
function makeSomeCtrl() {
+ var identity = function (x) {return x;};
+ $scope = identity($scope)
return function($scope) {
...
And all of sudden, all the angular in the page "{{page.hello}}" instead of "Hello, World"
Why on Earth...?
Edit: Here's a Plunker demonstrating this behavior: http://plnkr.co/edit/lztwTNdAN4baVDtFLCX4?p=preview
Resolution
So, $scope wasn't in scope. D'oh! That is both meta and embarassing.
Edit again: Not resolved
The code in the Plunker, does not reflect the original code I was trying to debug. ie, the problem with the original code wasn't a scope error. That was an error I made while drafting the Plunker. Here's an updated Plunker that more accurately reflects the code I'm dealing with: http://plnkr.co/edit/iswQq2qqRyQjsPA4Bkk6?p=preview
(function() {
'use strict';
function addSomeValue(obj, x) {
obj.value = x;
}
function makeCtrl(x) {
function Ctrl($scope){
addSomeValue($scope, x)
}
return Ctrl;
}
angular.module('modal-example', [])
.controller('Ctrl', ['$scope', makeCtrl("Hello!")]);
}());
Results in a nice fat "{{value}}" in the rendered page.
This is an easy one, $scope is not defined before you try to call it.
function makeCtrl(someVar) {
function identity(o){return o;}
//Where did I come from?
$scope = identity($scope)
function RandomIdentityCtrl($scope){
$scope.beforeIdentity = "Before Identity";
$scope.afterIdentity = "After Identity";
}
return RandomIdentityCtrl;
}
If you simply move it down into the constructor function, you will see it works just fine:
function makeCtrl(someVar) {
function identity(o){return o;}
function RandomIdentityCtrl($scope){
$scope.beforeIdentity = "Before Identity";
//Now I work! Yay!
$scope = identity($scope)
$scope.afterIdentity = "After Identity";
}
return RandomIdentityCtrl;
}
Update
After reviewing the updates here: http://plnkr.co/edit/iswQq2qqRyQjsPA4Bkk6?p=preview
It would appear you just made a couple of typos.
One in your function:
function makeCtrl(x) {
function Ctrl($scope){
addSomeValue($scope, x)
}
//Should be 'Ctrl'
return RandomIdentityCtrl;
}
And one in your HTML template:
<!-- Should be "Ctrl" -->
<div class="container" ng-controller="RandomIdentityCtrl">
Fixing these again results in desired behavior: http://plnkr.co/edit/eKdDPYylTCS1czwKKWew?p=preview
You can't access $scope in makeCtrl because Angular won't inject it into your function. If you move the line $scope = identity($scope) into RandomIdentityCtrl, your code works fine.

How to set a variable in different controller in AngularJS?

I'd like to do simple notifications in angular. Here is the code I've written.
http://pastebin.com/zYZtntu8
The question is:
Why if I add a new alert in hasAlerts() method it works, but if I add a new alert in NoteController it doesn't. I've tried something with $scope.$watch but it also doesn't work or I've done something wrong.
How can I do that?
Check out this plnkr I made a while back
http://plnkr.co/edit/ABQsAxz1bNi34ehmPRsF?p=preview
I show a couple of ways controllers can use data from services, in particular the first two show how to do it without a watch which is generally a more efficient way to go:
// Code goes here
angular.module("myApp", []).service("MyService", function($q) {
var serviceDef = {};
//It's important that you use an object or an array here a string or other
//primitive type can't be updated with angular.copy and changes to those
//primitives can't be watched.
serviceDef.someServiceData = {
label: 'aValue'
};
serviceDef.doSomething = function() {
var deferred = $q.defer();
angular.copy({
label: 'an updated value'
}, serviceDef.someServiceData);
deferred.resolve(serviceDef.someServiceData);
return deferred.promise;
}
return serviceDef;
}).controller("MyCtrl", function($scope, MyService) {
//Using a data object from the service that has it's properties updated async
$scope.sharedData = MyService.someServiceData;
}).controller("MyCtrl2", function($scope, MyService) {
//Same as above just has a function to modify the value as well
$scope.sharedData = MyService.someServiceData;
$scope.updateValue = function() {
MyService.doSomething();
}
}).controller("MyCtrl3", function($scope, MyService) {
//Shows using a watch to see if the service data has changed during a digest
//if so updates the local scope
$scope.$watch(function(){ return MyService.someServiceData }, function(newVal){
$scope.sharedData = newVal;
})
$scope.updateValue = function() {
MyService.doSomething();
}
}).controller("MyCtrl4", function($scope, MyService) {
//This option relies on the promise returned from the service to update the local
//scope, also since the properties of the object are being updated not the object
//itself this still stays "in sync" with the other controllers and service since
//really they are all referring to the same object.
MyService.doSomething().then(function(newVal) {
$scope.sharedData = newVal;
});
});
The notable thing here I guess is that I use angular.copy to re-use the same object that's created in the service instead of assigning a new object or array to that property. Since it's the same object if you reference that object from your controllers and use it in any data-binding situation (watches or {{}} interpolation in the view) will see the changes to the object.

Using deeply nested object from JSON in AngularJS - strange behavior

I'm trying to understand how AngularJS sees an object from a deeply nested JSON. Here's an example plunker. The data comes from service and is assigned to $scope.data. The javascript code seems to want me to declare every level of the object first before usage, but referencing a deep level within object from the view HTML always works, and using the deep level in a function kinda works. It's rather inconsistent.
I'm not sure if my understanding of $scope is lacking, or if this has something to do with promise objects. Advise please?
HTML
<body ng-controller="MainCtrl">
Referencing nested obj in view works:
{{data.level1.level2}}
<br>
Using nested obj within declared scope var doesn't work:
{{nestedObj}}
<br>
Using nested obj in a function works but throws TypeError:
{{getLen()}}
</body>
Javascript
var app = angular.module('app', []);
app.factory('JsonSvc', function ($http) {
return {read: function(jsonURL, scope) {
$http.get(jsonURL).success(function (data, status) {
scope.data = data;
});
}};
});
app.controller('MainCtrl', function($scope, JsonSvc) {
JsonSvc.read('data.json', $scope);
// Using nested obj within declared scope var doesn't work
// Uncomment below to break whole app
// $scope.nestedObj = $scope.data.level1.level2;
// Using nested obj in a function works but throws TypeError
// Declaring $scope.data.level1.level2 = [] first helps here
$scope.getLen = function () {return $scope.data.level1.level2.length};
});
JSON
{
"level1": {
"level2": [
"a",
"b",
"c"
]
}
}
Your $http request is asynchronous.
app.controller('MainCtrl', function($scope, JsonSvc) {
JsonSvc.read('data.json', $scope);
//$scope.data.level1.level2 doesn't exist yet at this point in time
//and throws an exception
$scope.nestedObj = $scope.data.level1.level2;
//$scope.data.level1.level2 doesn't exist yet at this point in time
//and throws an exception
//once Angular does dirty checking this one will work since the
//$http request finished.
$scope.getLen = function () {
return $scope.data.level1.level2.length
};
});
Since you have three scope objects that rely on that data it would be best to assign those in the call back.
app.factory('JsonSvc', function ($http) {
return {read: function(jsonURL, scope) {
$http.get(jsonURL).success(function (data, status) {
scope.data = data;
scope.nestedObj = scope.data.level1.level2;
scope.getLen = function () {
return scope.data.level1.level2.length;
};
});
}};
});
If you do not want to set it all up on the call back, you could also use $broadcast() and $on()
app.factory('JsonSvc', function ($http, $rootScope) {
return {
read: function (jsonURL, scope) {
$http.get(jsonURL).success(function (data, status) {
scope.data = data;
$rootScope.$broadcast("jsonDone");
});
}
};
});
app.controller('MainCtrl', function ($scope, JsonSvc) {
JsonSvc.read('data.json', $scope);
$scope.name = "world";
$scope.$on("jsonDone", function () {
$scope.nestedObj = $scope.data.level1.level2;
$scope.getLen = function () {
return $scope.data.level1.level2.length;
};
});
});
Ray, another option is to return the $http.get call since its a promise and use the .then() function to declare $scope.nestedObj or anything else you want to do with data once it returns.
Here's my example: http://plnkr.co/edit/GbTfJ9
You can read more about promises in Angular here: http://docs.angularjs.org/api/ng.$q

Categories

Resources