Refresh list after server callback in AngularJS - angularjs

I fetch a collection from the server and I would like to get detail for each item. All requests are received correctly, but the paragraph Loading... doesn't hide.
<h2 ng-repeat-start="server in hypervisors track by server.ip | orderBy:server.ip">
{{server.ip}}
</h2>
<div ng-repeat-end>
<p ng-hide="{{server.loaded}}" class="ng-hide">Loading...</p>
When I uncomment the line in controller before post everything works fine.
vmwareStatusApp.controller('Home', function ($scope, $http) {
$http.post('Home/ListHypervisors').success(function (data) {
$scope.hypervisors = data;
$scope.listLoaded = true;
$scope.hypervisors.forEach(function (item) {
//item.loaded = true; // this line works
$http.post('Home/HostInfo', { 'ip': item.ip }).success(function (data) {
$scope.hypervisors[0].loaded = true;
item.loaded = true;
item.detail = data;
})
.error(function(data) {
item.loaded = true;
item.error = data;
item.displayError = true;
});
});
});
});
There are many posts about refreshing view, but I haven't found any working for me. Neither anti-patter with calling $digest() didn't work, because of multiple callback. Which part of AngularJS tutorial have I skipped?

Just remove the braces from your ng-hide like this
ng-hide="server.loaded"
ng-hide and angular directives should be read like this :
ng-directive = "somethingAngularWillInterpret"
The opposite exemple is in your HTML angular will not know what he should interpret instead of just showing some text
<b>server.loaded</b> will show a bold "server.loaded"
To notice angular that he need to interpret we will use the braces
<b>{{somethingAngularWillInterpret}}</b> will show a bold result of the interpretation
EDIT :
So doing this ng-hide="{{server.loaded}}" is probably saying to angular to interpret the result of the server.loaded interpretation like a var named true or a var named false (just speculation, i need to try it).
Just tested it, this just lead to a syntax error.

Related

ng-show and/or ng-if do not function 100% of the time

I have a Chrome extension uses an ng-show expression that checks a variable of Chrome storage, and displays a big blue button if the value is at zero. When opening the extension, however, the button could show up on the first click, or you may have to close and reopen the extension several times before it shows up (simply showing a blank body). This has been incredibly frustrating and is obviously a UX problem that I would like to fix before I publish the extension to the public.
Here is the div code from within the main view of the extension:
<div id="no_vseeks" ng-show="vseeks.length === 0">
<div class="big-button-container"><h1>CREATE</h1></div>
</div>
The expression is referring to an array called 'vseeks' in the Chrome local storage.
And here is what the extension is supposed to output:
But this is what the extension will show (seemingly) at random.
Please inform me if I need to include more code or images.
EDIT: Here's the main controller where the vSeeks array is being retrieved from Chrome storage. The console logs show that after the chrome.storage.get function is called, the array is present, but yet I still get a blank view.
app.controller('mainController', function($scope, $window) {
$scope.toggleAcc = function($event) {
var currentAcc = $event.currentTarget;
currentAcc.classList.toggle("active");
var panel = currentAcc.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
}
$scope.sendID = function(id) {
currentVID = id;
$window.location.href = "#!delete";
}
var noVseeks;
var home_button;
var newV_button;
console.log('controller reached', $scope.vseeks);
chrome.storage.sync.get('userData', function(items){
$scope.vseeks = items.userData.vSeeks;
console.log('inside chrome storage get', $scope.vseeks);
home_button = document.getElementById('home_button');
newV_button = document.getElementById('newV_button');
console.log('variables: ', home_button, newV_button);
if ($scope.vseeks.length < 1) {
home_button.style.visibility = "hidden";
newV_button.style.visibility = "hidden";
}
else {
newV_button.style.visibility = "visible";
if (home_button.style.visibility == "visible") {
home_button.style.visibility = "hidden";
}
}
});
});
I am unfamiliar with Chrome.storage.sync but it must be returning a non-angularjs promise (i.e. not $q). In that scenario, the function you are running upon resolve is executing outside of the angular digest cycle -- angular doesn't know it should be doing anything. The way to force angular to run its cycle is to use $scope.$apply. This will synchronize the model to the view and vice versa.

How to get ui-sref working inside trustAsHtml?

I have a activity state, and when there are no activities I would like to display a message. So I created a if/else statement that checks if the $scope activities has any content, if not it injects a certain code into the template.
if(!$scope.activities.length){
var empty = function(){
$scope.renderHtml = function (htmlCode) {
return $sce.trustAsHtml(htmlCode);
};
$scope.body = '<div>There are no activities yet, <a ui-sref="home.users">click here to start following some friends!</a></div>';
}
empty()
}
The problem is that ui-sref doesn't work, a normal 'a href` does work though. Are there any solid work arounds for this problem?
To get this work I created a element with ng-show,
%div{"ng-show" => "activitiesHide"}
And this js,
activitiesService.loadActivities().then(function(response) {
$scope.activities = response.data;
if(!$scope.activities.length){
$scope.activitiesHide = response.data
}
})
I place the results from the service in the activities scope, and then check in the js if it has content. If not activate the activitesHide show.

Server side pagination of AngularJS ng-grid

I am trying to implement this server side pagination example of ng-grid mentioned here http://angular-ui.github.io/ng-grid/ . Unfortunately, I do not quite understand the code.
Here is my situation:
1. Say I have a page which has 2 text boxes and a button. I would like to post the values of these two text boxes to a web service on ng-click of the button. Returned json should be displayed as grid. But the code in the plunker http://plnkr.co/edit/50vJrs?p=preview
$scope.getPagedDataAsync = function (pageSize, page, searchText) {
setTimeout(function () {
var data;
if (searchText) {
var ft = searchText.toLowerCase();
$http.get('largeLoad.json').success(function (largeLoad) {
data = largeLoad.filter(function(item) {
return JSON.stringify(item).toLowerCase().indexOf(ft) != -1;
});
$scope.setPagingData(data,page,pageSize);
});
} else {
$http.get('largeLoad.json').success(function (largeLoad) {
$scope.setPagingData(largeLoad,page,pageSize);
});
}
}, 100);
};
will render the grid on page load (which I do not want). What I dont understand is how to associate the $scope.getPagedDataAsync function with a ng-click?
The html code doesnt have any textbox for searching through the grid even though in the controller they have $scope.filterOptions. How is the search happening the in plunker code?
Wish there was more documentation on the site.
Thank you
In the plunker, the function quoted in your question is immediately invoked:
$scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage);
Does commenting out that line have the desired effect?
As for the filter, it's probably there as a convenience so you can add a filter text field yourself. It is defined in an object so you can use a custom directive or ng-include block.

Angular.js - Jade, Form Submission

I'm new to Angular and I'm building my first realtime page based on the boiler plate from:
https://github.com/jimakker/angular-express-bootstrap-seed
I'm not able to get my first form to submit. In fact, nothing happens when I click the button. Given below are the relevant snippets from the code:
Partial View:
.row
form(ng-controller='RegisterCtrl')
#accordion.panel-group
//- Panel 1
.panel.panel-default
.panel-heading
h4(class='panel-title')
a(data-target='#collapse1', data-toggle="collapse", data-parent="#accordion", class="left-m-1em cursor-pointer") Basic Information
#collapse1.panel-collapse.collapse
.panel-body
.row
.col-lg-2(ng-controller='DropdownCtrl')
select(id="gender", ng-model='register.gender', ng-init="getValues('gender')", ng-options='r.value for r in results track by r.key', chosen, class="form-control", data-placeholder="Gender", data-toggle="tooltip", data-trigger="hover", data-placement="top", title="Gender")
option(value="")
//- More panels in between and finally, Panel 6
.panel.panel-default
.panel-heading
h4(class='panel-title')
a(data-target='#collapse6', data-toggle="collapse", data-parent="#accordion", class="left-m-1em cursor-pointer") Family
#collapse6.panel-collapse.collapse
.panel-body
.row
.col-lg-3.col-lg-offset-5
button(type="button", class="btn btn-success btn-lg", ng-click="saveProfile")
span(class="glyphicon glyphicon-ok-circle")
| Submit
I looked at the rendered output and confirmed that the Submit button is indeed within the form tag.
Controller:
function RegisterCtrl($scope, $http) {
$scope.register = {};
$scope.saveProfile = function(item, event) {
alert("called this!");
var json = {
gender: $scope.register.gender,
marital_status: $scope.register.marital_status,
dob: $scope.register.dob,
height: $scope.register.height,
weight: $scope.register.weight,
complexion: $scope.register.complexion,
health: $scope.register.health
};
var responsePromise = $http.post("/api/register", json, {});
responsePromise.success(function(dataFromServer, status, headers, config) {
console.log(dataFromServer.title);
});
responsePromise.error(function(data, status, headers, config) {
alert("Submitting form failed!");
});
};
}
RegisterCtrl.$inject = ['$scope', '$http'];
I'm not even hitting the first alert statement and I'm totally unsure why. The other controller DropdownCtrl (used for individual form elements) works just fine and I'm able to populate the values dynamically using the controller. Please help me find the missing piece.
The syntax is ng-click="saveProfile()" rather than ng-click="saveProfile"
Note also that this won't pass any arguments to the function, if you want to do that then you need to pass them inside the markup too.
Found the problem. Had some stray code in the controller file that read:
` function MyCtrl2() {
}
MyCtrl2.$inject = [];
function RegisterCtrl() {
}
RegisterCtrl.inject = [];`
And since this was in the file after the actual definition, it messed up the functionality.

Angularjs: How do you use ng-show?

I'm trying to check if something exists and show a button based on that. What am I doing wrong and how can I fix it?
My code looks like this:
$scope.isURL = function(url) {
$http.get(url).success(function (data) {
if (data === 302) {
return true
}
});
};
my HTML:
<ul ng-repeat="foo in foos">
<button ng-hide="isURL(foo.url)">visit site</button>
<button ng-show="isURL(foo.url)">remove bookmark?</button>
</ul>
Error loop I'm getting:
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: []
The biggest problem is that you are setting up a binding on a function that is returning a new promise each time.
The $digest cycle is going to fire, and evaluate the result of your function and determine that the result has changed, making it dirty. This will trigger another $digest loop that will continue ad infinitum.
A better option would be to check each of the urls, and set a property on the foo objects if they are good.
app.controller('displayCtrl', ['$scope','$http', function(scope,$http){
var foos = [
{name: 'foo-1', url:'assets/foo.html'},
{name: 'foo-2', url:'assets/bad.html'}
];
angular.forEach(foos, function(foo){
$http.get(foo.url).success(function (data) {
if(data === 302){
foo.isUrl = true;
}
});
});
scope.foos = foos;
}]);
Which you can then bind to in your markup like this:
<ul ng-repeat="foo in foos">
<button ng-hide="foo.isUrl">visit site</button>
<button ng-show="foo.isUrl">remove bookmark?</button>
</ul>
You may want to try something like this instead:
$scope.urls = {};
$scope.isURL = function(url) {
if (angular.isUndefined($scope.urls[url])) {
$scope.urls[url] = false;
$http.get(url).success(function(data) {
if (data === 302) {
$scope.urls[url] = true;
}
return data;
});
}
return $scope.urls[url];
};
That will also prevent you from checking each URL more than once. I am not sure why you are checking for data === 302, but I assume you know what you are doing there. If you are trying to check the status code, that will not work, you would need to use this instead:
$http.get(url).then(function(response) {
if (response.status === 302) {
$scope.urls[url] = true;
}
return response;
});
Edit
Documentation on how to use ngShow (and other directives) can be found on the AngularJS web site. The if the expression evaluated in the ngShow directives is truthy the element will be shown. In your code sample, $scope.isURL(...) does not return a value.

Resources