ng-bind value not updating second time when updating from controller - angularjs

i am trying to bind value in label when i get signal in session.
for first it shows values in label but when i send signal second time it shows blank label and is not updating value.
code i am using
HTML
<div class="modal-content">
<h4>Incoming Call From...</h4>
<label class="alignCenter incomingReason">{{requestedCall.reason}}</label>
<label class="alignCenter">{{requestedCall.hname}}</label>
</div>
Controller
session.on("signal:chat", function (event) {
var data = JSON.parse(event.data);
$scope.requestedCall.reason = data.complain_name;
$scope.requestedCall.hname = data.username;
$scope.PlayRingtone();
$scope.$apply();
$scope.showModel();
});
when i send signal , i gets data in var data = JSON.parse(event.data);
i always have to use $scope.$apply() other wise it doesn't bind value for first time also but for second time it doesn't work at all.
i have tried $timeout , $digest but nothing works at all , any help would be appreciated.

When we are out of angular, things doesn't work. So if you are doing something in jQuery or any other library angular will not know what has been changed. For that you've to tell angular explicitly by using $apply or $digest
$scope.$apply(function () {
$scope.requestedCall.reason = data.complain_name;
$scope.requestedCall.hname = data.username;
$scope.PlayRingtone();
$scope.showModel();
});
Let me know if it works!

Related

Angular: Data on Component's View Only Update When Performing Click Action

I forked an example from Angular 1's tutorial:
https://plnkr.co/edit/I48XFq
2 controllers (MainCtrl and AltCtrl) reference to the same Hero data from one dataService
MainCtrl and AltCtrl use a heroDetail component to render view of data
My setup:
dataService udpates data.time every 3 seconds using setInterval (I'm trying to not use Angular's $interval to get data rendered on view)
.factory('dataService', function() {
var data = {};
data.location = "Safe House";
data.count = 0;
data.time = new Date();
setInterval(function() {
data.time = new Date();
data.count++;
}, 1000);
data.updateLocation = function(origin) {
if (origin === 'click') return;
data.location = "Safe House #" + data.count;
}
return data;
});
In the heroDetail view, I put a button that invoke dataService.updateLocation('click'). Invoking from this button will do nothing, just return.
Also in the heroDetail controller, there's a setInterval to call dataService.updateLocation('setInterval') that actually update data.location
function HeroDetailController(dataService) {
var $ctrl = this;
$ctrl.update = function() {
dataService.updateLocation('click');
}
setInterval(function() {
dataService.updateLocation('setTimeout');
}, 3000); }
Result:
The service's data though gets udpate via background setInterval, but is not rendered on component view
But when I click on the front-end button, data is rendered with latest udpate, dispite the button just do nothing on data.
Could you help to explain why and how data got updated from service to the view in this case?
Thank you!
Using built-in $interval service instead of window.setInterval may solve your problem. AngularJs $interval documentation
To understand the problem, first read about JavaScript event loop. Event loop explained here
AngularJS $digest loop is based on event loop and after each digest cycle, it updates DOM according to the model that is two-way bound to the view. $digest cycle explained here
I think that you should add to your "setInterval" function the following line of code:
data.location = "Safe House #" + data.count;
Hope this helps.

Loading data in ng-repeat after $http

I am trying to load a number of elements in a div from json via $http call. But whatever I try the list remains empty. Here is the code.
<div class="submenu" >
<div class="menuitem" ng-repeat="item in navigator" >{{item}}
{{item.label}}
</div>
It is an abstract state and I have assigned controller greetingctrl to it in routes. The JS code is
app.controller('greetingCtrl',function($scope,$cookieStore,$timeout,$state,msg,SERVICE,RestService,$stateParams){
$scope.list = [];
$scope.navigator;
$scope.options.loading = false;
var currentmsg;
$scope.user = $cookieStore.get('userinfo');
$scope.init = function(){
var url = SERVICE.greetingMsg;
var data = {
providerID : $cookieStore.get('userinfo').providerId,
loginID : $cookieStore.get('userinfo').loginId,
action : "GET_MESSAGE"
}
RestService.post(url,data).then(function(res){
$scope.navigator = res.messages;
},
function(err){
console.log(err);
});
}
Here I can successfully receive the data but the data in the list never comes. RestService.post is $http method I have defined in a service.I am using angular 1.5.8 and I am new to angular.
EDIT: Removed ng-show and ng-if. Still the data is nnot showing
You need to check two variables:
- showmenu I don't see its value changing at all so it's always false.
- loadingisDone same as the previous.
And remember to call $scope.init somewhere.
what is the ng-if tag contains, it should have some conditions to check
change to
0'>
Try if it works
You dont need to use ng-if and ng-show both directives on same tag.
You can use either one to display that DIV by using && and || operators.
Please check the if the value of variables are updating properly.
For async execution use $scope.$apply to update your scoped data.
RestService.post(url,data).then(function(res){
$scope.$apply(function() {
$scope.navigator = res.messages;
});
}

Angularjs $scope is not updated

I am developing an angular-ionic-firebase application. I am struggling on an issue where I am unable to update a $scope in my html. My must resolve {{uevent}} and update the html with the result of {{uevent}}. My html code is below.
**<ion-view view-title="{{uevent}}">**
<ion-tabs class="tabs-stable tabs-icon-top">
<ion-tab title="Buddies" icon="ion-ios-people" ng- click="showBuddies(a)">
</ion-tab>
<ion-tab title="Summary" icon="ion-navicon" ng-click="billSummary()">
</ion-tab>
</ion-tabs>
my angular code is below. CurrUser is a factory. I've defined an empty $scope.uevent which I am expecting to update using a value returned from a factory.
var eventid = CurrUser.getEventid();
$scope.uevent = " ";
function updateEvent(desc) {
$scope.uevent = desc;
console.log($scope.uevent);// I am able to see the value returned from the factory. This function is executed below in the for loop.
};
// promise that returns a value from the factory - CurrUser.
CurrUser.getEventdesc(eventid).then(function (result) {
var description = result;
var desc;
for (var itemID in description) {
var tmp = description[itemID];
desc = tmp.Description; // This contains the value that must be updated to $scope.uevent
updateEvent(desc); // Calls the function defined above to update $scope.uevent.
};
});
I've been on this since last night without any clues. Any help is greatly appreciated and as always, thanks for your time.
UPDATE #1:(07 July)
When i added a timeout of 1 sec, the view was updated to the correct value.
function updateEvent(desc) {
$timeout(function(){
$scope.$apply(function () {
$scope.uevent = desc;
})
},1000);
};
Regards,
There are 2 execution context when You work with AngularJS - Angular Context and JavaScript Context.
When you are changing the data in AngularJS Context, the digest loop begins and all data updates, but when you change data in the JavaScript Context (e.g setTimeout, setInterval and so on), Angular doesn't know about the changes so it doesn't update the data.
In JavaScript Context you must change your data in scope.$apply() method to run the digest loop manually.
So your code will look like
var eventid = CurrUser.getEventid();
$scope.uevent = " ";
function updateEvent(desc) {
$scope.$apply(function(){
$scope.uevent = desc;
});
console.log($scope.uevent);// I am able to see the value returned from the factory. This function is executed below in the for loop.
};
// promise that returns a value from the factory - CurrUser.
CurrUser.getEventdesc(eventid).then(function (result) {
var description = result;
var desc;
for (var itemID in description) {
var tmp = description[itemID];
scope.$apply(function(){
desc = tmp.Description; // This contains the value that must be updated to $scope.uevent
})
updateEvent(desc); // Calls the function defined above to update $scope.uevent.
};
});
For more.If there is an Angular JS alternative, you must use it,because it runs te digest loop automatically($timeout instead of setTimeout(), $interval instead of setInterval())
Try this; $apply is used to trigger $digest .
function updateEvent(desc) {
$timeout(function(){
$scope.uevent = desc;
$scope.$apply();
},0)
};
Where is your controller defined in the html? Or is it in your app.js. Anyways, for a start can you do a $scope.$apply in your updateEvent function?
function updateEvent(desc) {
$scope.$apply(function(){
$scope.uevent = desc;
});
console.log($scope.uevent);
};
I dont know what happens in your getEventDesc() method but if there is a non-angular ajax request or something, then it might need the $apply to trigger the digest cycle and update watchers.
Detailed explanation below.
Reference: This awesome informative post -> https://github.com/angular/angular.js/wiki/When-to-use-$scope.$apply()
AngularJS provides wrappers for common native JS async behaviors:
Events => ng-click
Timeouts => $timeout
jQuery.ajax() => $http
This is just a traditional async function with a $scope.$apply() called at the end, to tell AngularJS that an asynchronous event just occurred.
$scope.$apply() should occur as close to the async event binding as possible.
Do NOT randomly sprinkle it throughout your code. If you are doing
if (!$scope.$$phase) $scope.$apply() it's because you are not high enough in the call stack.
Whenever possible, use AngularJS services instead of native. If you're creating an AngularJS service (such as for sockets) it should have a $scope.$apply() anywhere it fires a callback.

Reload a list with angularjs

I'm just starting to play with angularJS, so maybe I'm asking something easy to do, but I can't find the way to do it.
The situation is the following: I have a list that's populated by an ng-repeat taking the values from a scoped controller variable. This variable is loaded on page load by an jsonp call, and this works fine.
The problem comes when I need to reload this list based on another select. For example, if a select 'day' value in the select I need to show some values and when I select 'week' I need to show others (also loaded via ajax).
What I've tried is to have a service that loads the data and returns it, and in the controller have two methods, one for the first load and another for the second one that does $scope.apply with the variable. I then call this second method on select value change (I've done it with jquery to simplify it until I can fix this).
This is part of my HTML
<div x-ng-controller='LeaderboardCtrl'>
<select id='leaderboard-select'>
<option value='day'>day</option>
<option value='week'>week</option>
<option value='month'>month</option>
</select>
<div x-ng-repeat='p in leaderboard'>
<p>{{p}}</p>
</div>
</div>
And this is part of the code that affects this functionality
var lead = angular.module("lead",[]);
function LeaderboardCtrl($scope,$attrs,$http,jtlanService) {
$scope.leaderboard = [];
$scope.period = 'day';
var data = {
period:$scope.period
};
$scope.loadLeaderboard = function(){
myService.loadLeaderboard(data).then(function(leaderboard) {
$scope.leaderboard = [];
$scope.leaderboard.push.apply($scope.leaderboard,leaderboard);
});
}
$scope.reloadLeaderboard = function() {
myService.loadLeaderboard(data).then(function(leaderboard) {
$scope.$apply(function() {
$scope.leaderboard = [];
$scope.leaderboard.push.apply($scope.leaderboard,leaderboard);
});
});
}
$scope.loadLeaderboard()
}
lead.service("myService",["$http", function($http) {
var myService = {
loadLeaderboard : function(data) {
var promise = $http.jsonp("/widget/leaderboardJSONP?callback=JSON_CALLBACK&_="+new Date(),{
params:data,
cache:false,
ajaxOptions: { cache: false }
}).then(function(response) {
return response.data;
});
return promise;
}
};
return myService;
}]);
$("#leaderboard-select").change(function(){
scope.period = $("#leaderboard-select").val();
scope.reloadLeaderboard();
});
Here's a fiddle with the code: http://jsfiddle.net/WFGqN/3/
Your fiddle is riddled with issues:
There's no ng-app in your mark-up
You need to change the second Framework Extensions dropdown to one of the "No wrap" options
Your service needs to be defined above your controller
Your controller is referencing "jtlanService" but you've defined "myService"
Your $http.jsonp call isn't going to work as is, but you could use can use the echo service (see Ajax Requests on the left side) to emulate requests
You can't and shouldn't be using jQuery events to call Angular controllers. You should use ng-change and not $().change (and even if you were using jQuery for event binding, you should be using $().on('change')).
You didn't need to use $scope.$apply in your loadLeaderboard function, since when you're calling it, you were already inside of of an $apply call.
There's no need for 2 load+reload leaderboard methods.
And after all that, you don't actually need jQuery.
Here's a fiddle that fixes things up and I think gets you what you want: http://jsfiddle.net/WFGqN/5/. You'll of course need to fix the service on your end, but you get the idea.
I recommend reading this SO answer: "Thinking in AngularJS" if I have a jQuery background?

Databinding in angularJS not being updated - UI does not show change in $scope variable

I'm running into a problem with AngularJS where I use a callback on a custom service in order to pass data from one controller to another.
In particular, I'm trying to create a very simple logging service in which one controller registers a listener function with the service to receive updates when a message is logged, and the other controller logs a message when a button in the UI is clicked (triggering the listener in the first controller).
The listener function then updates a $scope.messages variable to show the newly logged message in the UI. However, while the newly arrived message arrives in the listener function, the UI is not updated.
I believe this is because AngularJS is not aware that $scope.messages is being updated.
However, trying to wrap the update of $scope.messages with $scope.$apply has brought no avail ($apply already in progress).
HTML Code:
<div ng-app="myApp">
<div ng-controller="ButtonCtrl">
<button type="button" ng-click="logMessage()">Button</button>
</div>
<div id="console" ng-controller="ConsoleCtrl">
<div ng-repeat="consoleItem in messages">{{consoleItem.message}}</div>
</div>
</div>
Javascript Code:
var module = angular.module('myApp', []);
module.factory('MyConsole', function($rootScope) {
var listeners = [];
var myConsoleService = {};
myConsoleService.log = function(messageObj) {
angular.forEach(listeners, function(listener){
listener(messageObj);
});
};
myConsoleService.registerListener = function(listener) {
listeners.push(listener);
};
return myConsoleService;
});
function ConsoleCtrl($scope, MyConsole){
$scope.messages = [{"message":"First message!"}];
MyConsole.registerListener( function(msgObj){
// while this console.log call below works as expected, the $scope.messages.unshift call does not update the view
$scope.messages.unshift(msgObj.message);
console.log($scope.messages);
});
}
function ButtonCtrl($scope, MyConsole) {
$scope.logMessage = function () {
MyConsole.log({message:"myLogmessage"});
};
}
Code can also be found for your convenience on JSFiddle: http://jsfiddle.net/G5LAY/3/
Any help would be greatly appreciated :-)
Thanks!
Your code is working, it's just that this line: $scope.messages.unshift(msgObj.message); only adds the message string to $scope.messages when your template expects $scope.messages to be a list of objects instead. So changing it to $scope.messages.unshift(msgObj); should do the trick.

Resources