Reputation: 43077
I'm trying to build an AngularJS app, which outputs an HTML table that I populate with json (the table's HTML is at the bottom of this question). I'm using application/json
data that I retrieve from my server.
When I do a simple curl http://myurl.local/todo/api/v1/tasks
, I get json with no problems. If I put a console.log();
inside this block, I'm clearly getting the json from the server.
getJson: function() {
var url = 'http://myurl.local/todo/api/v1/tasks';
var promise = $http.get(url);
return promise.then(function(result) {
console.log("Got data ->" + result.data);
return result.data;
});
}
I'm using Chrome to develop the app; when I run the app in Chrome, Chrome's javascript console throws this error: TypeError: Cannot read property 'length' of undefined
before I get to that console.log("Got data ->" + result.data);
line. It's a race condition.
The error is very clearly right here:
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 10, // count per page
}, {
total: data.length, // length of data <--- Broken, needs a promise?
The problem is that javascript isn't my primary language (it's Python); based on the googling I've done about this problem, I think I could fix this with a promise / .then()
in the right place. However I'm having difficulty understanding exactly how I should implement this in my javascript. I would like to find the way to fix the async json GET, and understand why it needs to be done that way.
Could someone explain how I should fix this, and why I should do it that way?
The JavaScript:
var App2 = angular.module('taskTable', ['ngRoute', 'ngTable']);
// Need to change AngularJS symbols when using flask + Jinja
App2.config(function($interpolateProvider) {
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
});
// Thank you PeteBD
// http://stackoverflow.com/a/12513509/667301
// Set up a controller to get json tasks...
App2.factory('getTasks', function($http) {
return {
getJson: function() {
var url = 'http://myurl.local/todo/api/v1/tasks';
var promise = $http.get(url);
return promise.then(function(result) {
return result.data;
});
}
}
});
App2.controller('tableCntl', function($scope, getTasks, $filter,
ngTableParams) {
var data = [];
getTasks.getJson().then(function(data) {
$scope.data = data;
});
data = $scope.data;
// Set up task table parameters
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 10, // count per page
}, {
total: data.length, // length of data
getData: function($defer, params) {
// use build-in angular filter
var orderedData = params.filter() ?
$filter('filter')(data, params.filter()) :
data;
// store filtered data as $scope.tasks
var pageCount = params.page();
var paramCount = params.count();
$scope.tasks = orderedData.slice((pageCount-1)*paramCount,
pageCount*paramCount);
// set total for recalc pagination
params.total(orderedData.length);
$defer.resolve($scope.tasks);
}
});
});
// Props... angular.bootstrap() is required if two apps on the same page
// http://stackoverflow.com/a/18583329/667301
angular.bootstrap(document.getElementById("Tasks"),["taskTable"]);
The HTML table via ngTable:
<div id="Tasks" ng-app="taskTable" ng-controller="tableCntl">
<p><strong>Filter:</strong> [[tableParams.filter()|json]]
<table ng-table="tableParams" show-filter="true" class="table">
<tbody>
<tr ng-repeat="task in $data">
<td data-title="'Description'" sortable="description"
filter="{'description': 'text'}">
[[task.description]]
</td>
<td data-title="'Priority'" sortable="priority"
filter="{'priority': 'text'}">
[[task.priority]]
</td>
<td data-title="'Entered'" sortable="entry">
[[task.entry]]
</td>
<td data-title="'Status'" sortable="status">
[[task.status]]
</td>
</tr>
</tbody>
</table>
</div>
Upvotes: 1
Views: 5892
Reputation: 1322
Definitely worth looking at ngResource - this will simply take out all the heavy lifting for you.
On another note, I suspect you don't need to do this:
App2.factory('getTasks', function($http) {
return {
getJson: function() {
var url = 'http://myurl.local/todo/api/v1/tasks';
var promise = $http.get(url);
return promise.then(function(result) {
return result.data;
});
}
}
});
i would change it to :
App2.factory('getTasks', function($http) {
return {
getJson: function() {
var url = 'http://myurl.local/todo/api/v1/tasks';
return $http.get(url);
}
}
});
As $http returns the promise. That means this bit still works:
getTasks.getJson().then(function(data) {
$scope.data = data;
});
Upvotes: 3