AngularJs variable scope outisde function - javascript

I am getting data using socket into angularJS controller.
$rootScope.list1= '';
socket.emit('ticker', symbol);
socket.on('quote', function(data) {
$rootScope.list1 = angular.fromJson(data.substring(3));
//I can't call any function from here to use this variable
});
I want to use updated list1 variable in my code below but I am not able to as it's value is coming as ''.
This can be because I am trying to access it in my script prior to it being updated i.e. prior to the response received.
Is there any way where I can use the updated value of variable list1 in my code below.
Edit 1
As suggested by #Manish Singh in one of the answers, I tried $rootScope.watch.It is reflecting new value for above peice of code but not for code given below.
$rootScope.peers = [];
industrysearch.searchindustry(indussymbol).then(function(results) {
industrysearch.searchpeers($scope.industrystock[0]._source.industry).then(function(results1) {
for (var number_stocks = 0; number_stocks < results1.length; number_stocks++) {
$rootScope.peers.push(results1[number_stocks]);
}
});
});
$rootScope.$watch('peers', function(newVal1, oldVal1) {
console.log(newVal1); //prints []
});
one is normal variable and one is used as array.I can;t see any other difference.
Edit 2
$watchCollection is use for arrays/collection which I missed.Below code is working.
$rootScope.$watchCollection('peers', function(newVal1, oldVal1) {
console.log(newVal1);
});
Thanks for help!

How about using a watch on $rootScope
$rootScope.$watch('list1', function(newVal, oldVal) {
//Do Something
)};

Try "$applyAsync":
$rootScope.list1= '';
socket.emit('ticker', symbol);
socket.on('quote', function(data) {
$rootScope.$applyAsync(function(){
$rootScope.list1 = angular.fromJson(data.substring(3));
});
});

Related

Angular ionic badge count not updating

I am new to angular and believe i am not fully understanding the digest cycle.
I am trying to update a badge count in a ion-tab.(using ionic)
"ion-tab"
<ion-tab title="Requests" badge="data.badge" ng-controller="RequestTabCtrl" badge-style="badge-assertive" icon-off="ion-pull-request" icon-on="ion-pull-request" href="#/tab/requests">
<ion-nav-view name="tab-requests"></ion-nav-view>
I have written a factory that will store and array. this array is updated through socket.io
"notifications factory"
.factory('notifications',function(){
var list = [];
return{
all: function(){
return list;
},
add: function(data){
list.push(data);
},
length: function(){
return list.length;
}
};
});
.controller('RequestTabCtrl',function($scope,notifications){
$scope.data = {
badge : notifications.length()
};
});
My problem is that the badge count is not updating when the notifications array is updated through socket.io. I have checked that the array is being updated. In fact i can console log the array length and can see it it changing. Also i have set a scope variable in the ion-tab's child io-nav-view and as a result can see the expression {{requests.length}} be updated in this view.
.controller('RequestsCtrl', function($scope,notifications) {
$scope.requests = notifications.all();
})
I have tried $watch(in RequestTabCtrl) on notifications.length. i have tried calling $apply(in RequestTabCtrl) which results in a $digest already in progress. I have tried $timeout and see no positive result (in RequestTabCtrl and the factory length function). Help will me much appreciated.
thanks to AjinderSingh, the solution was found.
So two ways to go about this. First using the $interval approach:
.controller('RequestTabCtrl',function($scope,notifications,$interval){
$interval(function(){
$scope.data = {
badge : notifications.length()
};
},2000);
});
Second approach is to $broadcast from the factory after an item has been added to the array. followed by catching this event in the controller:
.factory('notifications',function($rootScope){
var list = [];
return{
all: function(){
return list;
},
add: function(data){
list.push(data);
$rootScope.$broadcast('update');
},
length: function(){
return list.length;
}
};
});
.controller('RequestTabCtrl',function($scope,notifications,$interval){
$scope.$on('update',function(){
$scope.data = {
badge : notifications.length()
};
});
});
I am choosing the second approach as it seems to be cleaner.
$ionicPlatform.ready(function() {
$cordovaBadge.promptForPermission();
$scope.setBadge = function(value) {
$cordovaBadge.hasPermission().then(function(result) {
$cordovaBadge.set(value);
}, function(error) {
alert(error);
});
}
});
For complete reference plz check https://www.thepolyglotdeveloper.com/2015/07/modify-the-badge-number-of-an-ionic-framework-app/

angularFire 3 way data binding won't update an function

I have a firebaseObject (MyFirebaseService.getCurrentUser()) bind to $scope.user.
After binding successful, I loop tho the object to see if the object contain "associatedCourseId" equal to some value ($stateParams.id). If does, the $scope.finishLessonCount count up. The problem is, when I add new Object inside the firebaseObject (that bindto user) via other page OR inside firebase, the finishLessonCount value won't change as what I expect for 3 way binding. I need to refresh the page to see the finishLessonCount reflect the true value. What is wrong? I want the finishLessonCount change using the compare function as I add more finishedLessons into the firebaseObject. Please see code below:
MyFirebaseService.getCurrentUser().$bindTo($scope, "user").then(function(){
for (var key in $scope.user.finishedLessons) {
if ($scope.user.finishedLessons.hasOwnProperty(key)) {
if ($scope.user.finishedLessons[key].associatedCourseId == $stateParams.id) {
$scope.finishLessonCount++;
}
}
};
console.log ($scope.finishLessonCount);
});
UPDATE 1 according to #Kato solution:
I decide to use Extending firebaseOject way to solute this problem. But still, it does not. I did not use factory here to simplify thing since I need to pass in courseId to do the operation. Here is my code:
function countLessons(lessons, courseId) {
var count = 0;
for(var key in lessons) {
if( lessons[key].associatedCourseId == courseId) {
count++;
}
}
return count;
}
var UserWithLessonsCounter = $firebaseObject.$extend({
$$updated: function(snap) {
var changed = $firebaseObject.prototype.$$updated.call(this, snap);
this.lessonCount = countLessons(this.finishedLessons, $stateParams.id);
}
});
var refTemp = new Firebase($rootScope.baseUrl + "users/" + $rootScope.userId);
var userTemp = new UserWithLessonsCounter(refTemp);
userTemp.$bindTo($scope, "userTemp").then(function(){
console.log($scope.userTemp);
});
userTemp.$watch(function() {
console.log("Does this run at all? " + $scope.userTemp.lessonCount);
});
I update the user object, the lessonCount value did not change unless I refresh the page. And the console.log inside $watch did not run at all. What is wrong?
The promise returned by $bindTo is called exactly once. It's not an event listener. You can't listen to this to get updated each time there is a change.
Please read the guide, start to finish, and read about Angular's $watch method before continuing down this route, as with some fundamental knowledge, this should not have been your first instinct.
A beginner approach would be to utilize $watch:
MyFirebaseService.getCurrentUser().$bindTo($scope, "user");
$scope.$watch('user', function() {
for (var key in $scope.user.finishedLessons) {
if ($scope.user.finishedLessons.hasOwnProperty(key)) {
if ($scope.user.finishedLessons[key].associatedCourseId == $stateParams.id) {
$scope.finishLessonCount++;
}
}
};
console.log ($scope.finishLessonCount);
});
Or, having familiarized with the AngularFire API, one might pick $scope.user.$watch() in place of the scope method, which would prove more efficient.
Having written a large portion of the AngularFire code, I would pick the $extend tool, which was added precisely for use cases like this:
// making some assumptions here since you haven't included
// the code for your firebase service, which does not seem SOLID
app.factory('UserWithLessonsCounter', function($firebaseObject) {
return $firebaseObject.$extend({
$$updated: function(snap) {
var changed = $firebaseObject.prototype.$$updated.call(this, snap);
this.lessonCount = countLessons(this.finishedLessons);
return changed;
}
});
});
function countLessons(lessons) {
var count = 0;
for(var key in lessons) {
if( lessons.hasOwnProperty(key) ) {
count++;
}
}
return count;
}
And now in your controller:
app.controller('...', function($scope, UserWithLessonsCounter) {
var ref = new Firebase(...);
var user = new UserWithLessonCounter(ref);
user.$bindTo($scope, 'user');
user.$watch(function() {
console.log($scope.user.lessonCount);
});
});

Angularjs cannot add data service response to scope variable

I have a function in my controller which request dataservice for data and I am trying to add to current scope variable but it is giving me undefined error
$scope.affiliates = d.data;
if (isNaN($scope.affiliate_id)){
var i = 0;
while (i < $scope.affiliates.length){
var affiliate_id = $scope.affiliates[i].affiliate_id.replace(/["']/g, "");
DataService.getAffiliateConversionApiService(affiliate_id).then(function(apiData){
$scope.affiliates[i].apiData = apiData;//ERROR IN HERE
});
i++;
}
}
TypeError: $scope.affiliates[i] is undefined
I have also tried returning data from dataService and set it outside but it always returns empty.
How can i resolve this?
Don't forget that getAffiliateConversionApiService is returning a promise (which means it is an async operation) therefore your while block will execute for every possible i value before you even get the result from getAffiliateConversionApiService.
Let's imagine that $scope.affiliates.length is 6. When your callback code inside the then is executed, your i will be 7.
One solution is to use angular.forEach instead of the while. However, if you still want to use the while you will need to store the i value in another variable:
while (i < $scope.affiliates.length){
var index = i;
var affiliate_id = $scope.affiliates[i].affiliate_id.replace(/["']/g, "");
DataService.getAffiliateConversionApiService(affiliate_id).then(function(apiData){
$scope.affiliates[index].apiData = apiData;
});
i++;
}
This is not really an answer, but here is some debugging that should help you out.
Also, I switched from using a while loop to using angular's forEach
$scope.affiliates = d.data;
if (isNaN($scope.affiliate_id)){
console.log($scope.affiliates); // what does this return?
angular.forEach($scope.affiliates, function(value, index){
console.log(value); // output the affiliate, if any
var affiliate_id = value.affiliate_id.replace(/["']/g, "");
DataService.getAffiliateConversionApiService(affiliate_id).then(function(apiData){
console.log(apiData); // see what is returned
$scope.affiliates[index].apiData = apiData; // still an error?
});
});
}

Ember.js computed property from store

I'm trying to get a simple count of objects returned by REST get request from the server to use in another controller in Ember.js
For this reason I need to make an additional request to the server. Basically here's my code and it almost works.. but not quite yet. Maybe someone can figure out why.
It return a PromiseArray, that's why I'm using .then() to access the properties .
App.TestController = Ember.ObjectController.extend({
totalCount: function() {
return this.store.find('question', {test: this.get('id')}).then(function(items) {
var count = items.get('content').get('length');
console.log(count); // This actually logs correct values
return count;
})
}.property('question')
})
It does what it suppose to do and I'm getting correct values printed out in the console.log(), but when I try to use {{totalCount}} in the view template I'm getting [object Object] instead of an integer.
Also, am I properly observing the questions property? if the value changes in its proper controller will the value update?
Thanks
The problem you are seeing is because your are returning a promise as the value of the property and handlebars won't evaluate that promise for you. What you need to do is create a separate function that observes question and then call your store there to update the totalCount-property. It would be something like this.
App.TestController = Ember.ObjectController.extend({
totalCount: 0,
totalCountUpdate: function() {
var that = this;
this.store.find('question', {test: this.get('id')}).then(function(items) {
var count = items.get('content').get('length');
console.log(count);
that.set('totalCount', count);
})
}.observes('question')
})
Alternatively totalCount might lazily set itself, like this:
App.TestController = Ember.ObjectController.extend({
totalCount: 0,
question: // evaluate to something,
totalCount: function() {
var that = this;
that.store.find('question', {test: that.get('id')}).then(function(items) {
var count = items.get('content').get('length');
that.set('totalCount', count);
})
}.observes('question').property()
})

angularjs: $watch two variables and do something if only one changes

I have a situation in which I want to monitor a specific variable.
$scope.$watch('action', function() { /* do something */ }
However, I only want to do something if $scope.id didn't change (if $scope.action changes it is possible that $scope.id has changed too.)
The only solution I can think of is
$scope.$watch('action', function() {
if(idHasChanhed === false){
/* do something */
}
idHasChanged = false;
});
$scope.$watch('id', function() { idHasChanged = true }
However, I was wondering if angular has a better solution than this, and I don't know if this solution will always work ( is the order in which the $watches are executed random !?)
My solution :
$scope.$watch('[action,id]', function() {
// called when action or id changed
});
Info : The string concatenation action + id will fail.
var action,id; // variables you need to watch
$scope.$watch('action + id', function() {
// actions
});
$watchGroup This function is introduced in Angular1.3. This works the same as $watch() function except that the first parameter is an array of expressions to watch.
Use $watchGroup
$scope.$watchGroup(['action', 'id'], function(newVal, oldVal) {
//write your code here
});

Categories