In parent scope (external one which wrap entire webapp) I define boolean variable if you're logged in.
$localForage.getItem('authorization')
.then(function(authData) {
if(authData) {
$scope.authentication.isAuth = true;
//token is added in http interceptor
} else {
$scope.authentication.isAuth = false;
}
}, function(){
console.log("error with getting authorization localForage after refresh");
}
);
It is basically working correct. Now I can build UI basing on this boolean with ng-if="$parent.authentication.isAuth". I also can display true/false like so <p>{{$parent.authentication.isAuth}}</p> in view and it is also working correct.
In one controller I want to use this boolean inside controller not in view. So I do if($scope.authentication.isAuth){ or if($scope.$parent.authentication.isAuth){ (I tried both) and this condition go to else even when <p>{{$parent.authentication.isAuth}}</p> in view of controller where I'm using this condition display true.
So it
<div ng-controller="ctrl">
<p>{{$parent.authentication.isAuth}}</p>
</div>
display true in paragraph and within controller named ctrl this condition if($scope.authentication.isAuth){ go to else... Why such weird behaviour?
if($scope.authentication.isAuth){
console.log($scope.authentication.isAuth);
console.log('true');
} else {
console.log($scope.authentication.isAuth);
console.log('false');
}
And it console.log false and "false" string.
As you set the value async ($localForage.getItem('authorization').then ...), it will be first false, then it might be set to true after the async operation has finished. Your view updates the value accordingly - everytime it changes - that's why you say it shows true in the view. It will be first false there, and after a few milliseconds will change to true. You don't neccessarily see that, but it still happens. The console.log is run before that async change happens, and as the if > else only runs once, it will only log the variable's state before it has been set to true.
Related
Angular js function updating some record. After updating record i am calling search method to show data on view.
But record does not updated before that search method call that does not get data so show null on view.
I have separate button for search on its ng-click this search method call. After some second if i click that button it shows data on view.
my code is,
vm.Update = function (value)
{
var test = value;
searchCriteria = {
From: vm.From,
To: vm.To,
Region: vm.Region,
City: vm.SelectedCity
}
surveyService.UpdateVisit(searchCriteria,value).then(function (d) {
var Confrm = JSON.parse(d.data.data);
if (d.data.status) {
toastr.success(Updated, {
autoDismiss: false
});
}
else {
toastr.error(errorMsg);
}
});
vm.searchVisit(0);
}
This searchvisit call and service unable to update data in database so i do not get any record on view. When i call this searchvisit method from separate button for searching it shows record with updated data.
Hopes for your suggestions how to pause execution before calling searchvisit method or any alternative that it gets any response than move execution control to searchvisit method.
Thanks
This is due to the asynchronous nature in JS.
From your code, surveyService.UpdateVisit(searchCriteria,value) returns a promise. Thus, when vm.searchVisit(0); is called, surveyService.UpdateVisit(searchCriteria,value) has not been resolved yet, meaning updating is still in progress and have not been completed. There for vm.searchVisit(0); shows records that are not updated.
If your second function is dependent on the values of the first function call, please add it as shown below inside the success callback.
surveyService.UpdateVisit(searchCriteria,value).then(function (d) {
var Confrm = JSON.parse(d.data.data);
if (d.data.status) {
toastr.success(Updated, {
autoDismiss: false
});
}
else {
toastr.error(errorMsg);
}
//Add this here.
vm.searchVisit(0);
});
I got an User list using ng-repeat via an API call.
For every User their is 5 categories and each category got 2-3 authorizations on true/false.
For every user/category/authorization I want a checkbox that will change the value of authorization.
When I check the checkbox of a User I want all his 5 categories + all the authorizations been check true and if I uncheck one authorization or categories of a User his checkbox will go false.
So if I recapitulate: there is a parent(User), child(Category) and grand child(Authorization).
I saw that we can use ng-model with ng-checked but in my checkbox, the ng-model is used for the boolean authorization (ng-model="authorization.Enabled") and for more than 1 child this no more work.
How can I manage this case ? Need a $watcher ?
Thanks for your help !
You can use ng-click on each child/grand child.
Pass parent object (user or cathegory) object in it and modify its boolean value on specific condition (when all childs are true or not)
You shouldn't use ng-click and ng-model together, you can avoid doing this by use ng-checked and ng-click on parent(user or cathegory) checkbox.
vm.authorizationCheckboxClick = function (user,category, authorization) {
authorization.booleanValue = !authorization.booleanValue;
if (authorization.booleanValue){
category.booleanValue = true;
category.authorizations.forEach(function(element) {
if(!element.booleanValue){
category.booleanValue = false;
break;
}
}, this);
}
else {
category.booleanValue = false;
}
if (category.booleanValue){
user.booleanValue = true;
user.categories.forEach(function(element) {
if(!element.booleanValue){
user.booleanValue = false;
break;
}
}, this);
}
else {
user.booleanValue = false;
}
}
This example function changing value of authorizations and then changing bolean values of parent category and user. You can bind this values to ng-checked directive
I have a dropdown with elements that get disabled when conditions are met. In the test, I check them for being disabled, but all tests fail and always return the element state as enabled (Clearly incorrectly. I have ensured that this is not a timing issue - refreshed the page and gave ample wait time with browser sleep - the elements are clearly disabled on the screen). There is an anchor within a list item. Please see image:
I have tried checking both the list item and the anchor, like so:
var actionDropDownList = $$('[class="dropdown-menu"]').get(1);
var checkOutButtonState = actionDropDownList.all(by.tagName('li')).get(6);
actionsButton.click();
actionDropDownList.all(by.tagName('li')).count().then(function(count){
console.log('THE NUMBER OF ELEMENTS IN THE DROPDOWN IS...............................................................' + count);
}) //verify that I have the correct dropdown - yes
checkOutButtonState.isEnabled().then(function(isEnabled){
console.log('CHECKING checkOutButton BUTTON STATE: ' + isEnabled);
}) //log state - shows incorrectly
I have also tried checking the button itself for disabled state (the element below is what I tried checking instead of the list element):
var checkOutButton = $('[ng-click="item.statusId !== itemStatus.in || checkOut()"]');
This failed as well.
Not sure which one I should check and why both are failing. How do I correct this and get it to show that the disabled button is...well, disabled.
TEMPORARY ADD ON EDIT:
For simplicity's sake, I am trying:
var hasClass = function (element, cls) {
return element.getAttribute('class').then(function (classes) {
return classes.split(' ').indexOf(cls) !== -1;
});
var checkOutButtonState = actionDropDownList.all(by.tagName('li')).get(6);
expect(hasClass(checkOutButtonState, 'disabled')).toBe(true);
It still fails, however, despite the element clearly having the class. Alec - your solution throws "function is not defined," I am not sure if I need something else for it to see jasmine. Tried, but can't find anything wrong with it, not sure why I can't get it to work.
Edit:
If I run...since it only appears to have one class:
expect(checkOutButtonState.getAttribute('class')).toBe('disabled');
I get "expected 'ng-isolate-scope' to be 'disabled'"
In a quite similar situation I've ended up checking the presence of disabledclass:
expect(checkOutButtonState).toHaveClass("disabled");
Where toHaveClass() is a custom jasmine matcher:
beforeEach(function() {
jasmine.addMatchers({
toHaveClass: function() {
return {
compare: function(actual, expected) {
return {
pass: actual.getAttribute("class").then(function(classes) {
return classes.split(" ").indexOf(expected) !== -1;
})
};
}
};
},
});
});
I am trying to toggle a class when clicking on the Save button but also call a function. I am using coffeescript. The function gets called but the variable never gets set to false.
div(ng-class="{'someclass':setListFocus}, ng-repeat="item in items")
a(ng-click="setListFocus=false;someFunction();")
span(class="gs-desktop") Save
// Delete user data.
a(ng-click="setListFocus=true")
span Edit
I assume that your small example is missing all kinds of data.
I would recommend either using controllerAs, for example:
<div ng-controller="myController as vm">
and then changing your bindings to vm.setListFocus.
Or another option would be to change your controller code like so:
function myController($scope) {
$scope.list = { focus: false };
}
And change your binding to list.focus instead. This will solve your scope inheritance problems.
You could begin someFunction() with toggling the value of setListFocus
$scope.someFunction = function(){
$scope.setListFocus = !$scope.setListFocus;
// ... rest of someFunction()
}
And then the angular template would be just this:
a(ng-click="someFunction()")
Another thing you could do is set up a toggle ListFocus function, that can take an optional callback parameter. This means you can toggle the listfocus between true or false, and optionally execute another function. I'm not going to continue answering in coffeescript because I'm not that familiar, and not everyone is.
$scope.toggleListFocus = function(andThen = false){
$scope.listFocus = !$scope.listFocus;
if(andThen==false) andThen();
}
//usage..
//toggle $scope.listFocus
enter code here
a(ng-click="toggleListFocus()")
//toggle then someFunction()
a(ng-click="toggleListFocus(someFunction())")
say I have a album list and user can add album
controller.albumList = function($scope, albumService) {
$scope.albums = albumService.query();
$scope.$watch('$scope.albums',function(){
$scope.albums.$save($scope.albums)
})
$scope.addalbum= function(){
$scope.albums.objects.push(album);
}
};
get a album list from server and show them
user can add album
watch the albums list ,when change happend save them to the server.
the problem is the $watch always fired, I did not even trigger the addalbum method, and every time I refresh the page a new album is created.
I follow the the code in todeMVC angular
here is the example code
var todos = $scope.todos = todoStorage.get();
$scope.newTodo = '';
$scope.editedTodo = null;
$scope.$watch('todos', function () {
$scope.remainingCount = filterFilter(todos, { completed: false }).length;
$scope.completedCount = todos.length - $scope.remainingCount;
$scope.allChecked = !$scope.remainingCount;
todoStorage.put(todos);
}, true);
please help me understand this
this is a solution:
$scope.$watch('albums', function(newValue, oldValue) {
if (angular.equals(newValue, oldValue)) {
return;
}
$scope.albums.$save($scope.albums);
}
After a watcher is registered with the scope, the listener fn is called asynchronously (via $evalAsync) to initialize the watcher. In rare cases, this is undesirable because the listener is called when the result of watchExpression didn't change. To detect this scenario within the listener fn, you can compare the newVal and oldVal. If these two values are identical (===) then the listener was called due to initialization.
More about a $watch listener: $watch at angularjs docs
Firstly, you do not have to specify the scope object when referencing to a property of the scope. So, replace:
$scope.$watch('$scope.albums', ...)
with the following:
$scope$watch('albums', ...)
Now about your issue. $watch is triggered each time the value of the object / property being watched changes. This includes even those cases when the values are yet to be assigned, such as undefined and null. Thus, if you wish that the save should happen only when a new album is added, you can have code similar to:
//Makes assumption that albums has a length property
$scope.$watch('albums.length', function () {
//Check for invalid cases
if ($scope.albums === undefined || $scope.albums === null) {
return;
}
//Genuine cases.
//Proceed to save the album.
});
With this, the $watch is still triggered in unwanted scenarios but with the check, you avoid saving when the album has not changed. Also, note that your $watch triggers only when the length of the albums object changes. So, if an album itself is updated (say an existing album name is changed), then this watch is not triggered. You can change the watch property based on your needs. The watch property mentioned here works only when a new album is added.