I have an ng-repeat with an ng-show inside. The variable passed to ng-show is not fully initiated until a promise in my controller resolves.
This is causing the ng-show to always end up reading a "falsey" object because it is reading the value before the promise finishes getting the correct results from the service.
Is there a way to cause the ng-show to wait until my objects are fully initialized?
You could use a control variable, like $scope.loaded = false and make your promise set it to true. Then you can use both conditions in your ng-show.
On the page load set a flag value.
app.controller({.......
$scope.flagPromiseWait = false;
.........
.........
var onSuccess = function (result){
.............
............
$scope.flagPromiseWait = true;
},
var onError = function(err){
............
}
});
and on HTML use
<div ng-show="$scope.flagPromiseWait">...........<div>
Related
I use angularjs and I have a problem with ng-if when I use a function that returns true or false in two API, the browser is freezes
self.isShow= function() {
service.getKioskLogByKioskId([stateParams.kioskId], function (data) {
self.kioskLog = data;
service.getKiosk([stateParams.kioskId], function (kiosk) {
self.kiosk = kiosk;
debugger
if (self.kioskLog.isConnected && self.kiosk.isActive)
return true;
else
return false;
});
});
}
and in html
ng-if="self.isShow()"
Angular's ng-if can't be an async, it expects to get true/false in synchronous manner.
Don't forget that EVERY angular directive creates a "watch" that will be invoked as part of angular's dirty check mechanism, If you make a "heavy" operation on it, it will stuck the browser.
Basically there are 2 wrong things in your code, the first one, your isShow is not returning boolean value at all, (it always returns undefined).
The second one, you are probably making an API call inside the service.getKioskLogByKioskId method.
In order to solve both of the issues, you can make the service.getKioskLogByKioskId call inside the constructor of you controller, (if it is a component there is $onInit lifecycle hook for that), then save the async result on the controller, and use it the view.
It should look something like that:
class MyController {
constructor(stateParams) {
this.stateParams = stateParams;
this.isShow = false; // initial value
}
$onInit() {
const self =this;
service.getKiosk([stateParams.kioskId], function (kiosk) {
self.kiosk = kiosk;
debugger
if (self.kioskLog.isConnected && self.kiosk.isActive)
self.isShow = true;
else
self.isShow = false;
});
}
}
// view.html
<div ng-if="$ctrl.isShow"></div>
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;
});
}
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.
Please see the fiddle:
http://jsfiddle.net/HB7LU/4089/
On window resize if you check the console, $scope.showName keeps getting toggled between true and false as expected. However the view does not update. It remains with the initialized value of true.
From my understanding, the {{}} or ng-bind provides 1 way binding from controller to the view, so the value in the view should update when it changes in the controller.
What am I missing?
The $scope only binds to the view on $digest cycles - your event doesn't trigger a digest cycle since there was no action taken. You have to call $scope.$apply() to trigger a view update.
Be warned tho, $scope.$apply() can throw an error if a $digest cycle is already in progress.
You are missing a call to $scope.$apply() since the event is being handled outside of an angular context you need to call $scope.$apply() to trigger a digest which will updated any watchers http://jsfiddle.net/HB7LU/4091/
function MyCtrl($scope, $window) {
$scope.name = 'Timothy';
$scope.showName = true
$scope.nickname = 'Tim'
angular.element($window).bind('resize', function() {
if ($scope.showName){
$scope.showName = false;
}
else
{
$scope.showName = true;
}
console.log($scope.showName);
$scope.$apply();
});
}
You need to add $scope.$apply(); after any scope manipulation outside Angular events. Add it as the last statement of the bind function.
missing a call to $scope.$apply()
Look at http://jsfiddle.net/HB7LU/4093/
http://jsfiddle.net/HB7LU/4094/
$scope.$digest();
Try with this code..
I have add $digest of scope alter resize
I have a checkbox, like:
<input type="checkbox" ng-model="isPreCheckIn" />
I'm getting isPreCheckin (boolean) from a service which uses $q and either returns from the server or localStorage (if it exists).
The call in the controller looks like:
deviceSettings.canCheckIn().then(function (canCheckIn) {
$scope.isPreCheckin = !canCheckIn ? true : false;
});
And deviceSettings.canCheckIn looks like:
function canCheckIn() {
var dfrd = $q.defer();
LoadSettings().then(function (success) {
return dfrd.resolve(localStorage.canCheckIn);
});
return dfrd.promise;
};
So, on first page load, the checkbox doesn't bind correctly to isPreCheckIn; in fact, if I do a {{isPreCheckIn}}, it doesn't either. If I switch off of that page and go back, it works.
It appears that canCheckIn is outside of angular, based on that assumption, you need to wrap your assignment within $scope.apply:
deviceSettings.canCheckIn().then(function (canCheckIn) {
$scope.$apply(function(){
$scope.isPreCheckin = !canCheckIn ? true : false;
});
});
This tells angular to recognize the changes on your $scope and apply to your UI.
I think you should wrap the following in a $apply:
function canCheckIn() {
var dfrd = $q.defer();
LoadSettings().then(function (success) {
scope.$apply(function() {
dfrd.resolve(localStorage.canCheckIn);
}
});
return dfrd.promise;
};
It sounds like a timing issue. You may need to put a resolve clause in your route to give this call time to run and then pass in the result as a DI value. Without knowing which router you are using it is impossible to give you an accurate answer, but you might look at the video on egghead.io regarding routes and resolve.