ng-repeat isn't loading my array of objects - angularjs

I have a function that returns several jsons via rest requests, and the data of these jsons are stored in a array.
Then this array put in $scope and use it in a ng-repeat, but isn't working.
//JS
async function exec_q(access_token, start_date,end_date,programa_gql){
var people = [];
...requests and filling the array...
people.push({
"atrib1": res.1 === null ? '' : res.1,
"atrib2": res.2 === null ? '' : res.2
}
return people
}
people = await exec_q(access_token, start_date,end_date,programa_gql)
$scope.people = people
//HTML
<tbody id="table_apd_body">
<tr ng-repeat="p in people">
<th>{{{$index + 1}}</th>
<th>{{p.atrib1}}</th>
<th>{{p.atrib2}}</th>
</tr>
</tbody>
Obs:. the function that call the code above is async as well to make the await works.

The ES6 promises used by async/await are not integrated with the AngularJS framework and its digest cycle.
people = await exec_q(access_token, start_date,end_date,programa_gql)
$scope.people = people
$scope.$apply();
Use $apply to integrate $scope changes.

//Remove extra { in {{$index + 1}}
<tbody id="table_apd_body">
<tr ng-repeat="p in people">
<th>{{$index + 1}}</th>
<th>{{p.atrib1}}</th>
<th>{{p.atrib2}}</th>
</tr>
</tbody>

Related

Angular template doesn't render data from controller

I'm setting up an Angular JS app to consume a Django REST API, and I'm stuck on the rendering of data.
I already asked another question (this), but the solution that I've been given doesn't work.
I was wondering that maybe there is something wrong in the API view, could it be a problem when trying to render the data from the Angular controller?
Anyway, this is my Angular app + template (edited as suggested in the other stackoverflow question)
base.html
<body ng-app="schoolApp" ng-controller="schoolCtrl as vm">
<p>Hello {{vm.name}}!</p>
<div>
<table class="table table-striped">
<thead>
<tr>
<th>Classroom</th>
<th>School</th>
<th>Floor</th>
<th>Academic year</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="classroom in vm.classrooms">
<td>{{classroom.classroom}}</td>
<td>{{classroom.school.school_name}}</td>
<td>{{classroom.floor}}</td>
<td>{{classroom.academic_year}}</td>
</tr>
</tbody>
</table>
</div>
</body>
app.js
var schoolApp = angular.module('schoolApp', ['ngResource']);
schoolApp.factory('Classroom', ['$resource', function($resource) {
return $resource('/classrooms/?format=json', {}, {
query: {
method: 'GET',
isArray: true,
}
});
}]);
schoolApp.controller('schoolCtrl', function($scope, Classroom) {
var vm = this;
vm.name = 'World';
Classroom.query().$promise.then(function(data) {
console.log('Success: '+JSON.stringify(data));
vm.classrooms = data;
}, function (reason) {
console.log('ERROR: '+JSON.stringify(reason));
});
});
I was thinking that maybe there is some problem on the view, so here's the REST API view
class HomePageView(TemplateView):
template_name = 'school_app/base.html'
class StudentViewSet(viewsets.ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentSerializer
class ClassroomViewSet(viewsets.ModelViewSet):
queryset = Classroom.objects.all()
serializer_class = ClassroomSerializer
What am I doing wrong?
UPDATE:
This is what I get
Data on the console: yes.
Data on the tables: no.
As you are using controllerAs syntax, you have binded all data to controller context. So you could get data on view using its alias like vm.classrooms
<tr ng-repeat="classroom in vm.classrooms">
Have you tried to output in the html the content of the variable vm.classrooms.
You can do it with <pre>{{vm.classrooms|json}}</pre>
It seems to me that you are not binding correctly the variables inside the table,
i can't see it clearly in the picture, it can be {{ classroom.school.academic_year }} ??

How get my controller to make GET request when tab is selected?

I am pretty new to angular and I am working on a data entry web page. The web page has three tabs. Vendor, Products and Types. I started working on the Types tab first. I'd be happy if I could just display the results of a GET request to my Rest API. My Rest API works:
# curl http://192.168.1.115:8080/type
[
{"_id":"56415e7703aba26400fcdb67","type":"Skiing","__v":0},
{"_id":"56417a8503aba26400fcdb68","type":"Bannana","__v":0},
{"_id":"56417a8d03aba26400fcdb69","type":"Carrot","__v":0},
{"_id":"56417a9603aba26400fcdb6a","type":"Beer","__v":0}
]
Here's the pertinent part of my html UPDATED I now have st-safe-src=all_typesbut still no joy ...
<div ng-controller="typeCtrl" class="tab-pane" id="types-v">
<p>The number {{3 + 4}}.</p>
<p>message is {{message}}</p>
<table st-table="displayedCollection" st-safe-src="all_types" class="table table-striped">
<tbody>
<tr ng-repeat="x in displayedCollection">
<td>{{x.type}}</td>
</tr>
</tbody>
</table>
</div> <!-- end Types Tab -->
... and here is my typeCtrl.js ...
app.controller("typeCtrl", function($scope,$http) {
$scope.type_to_look_for = "";
$scope.message = "this is the message. (from typeCtrl)";
$scope.itemsByPage=15;
$scope.all_types = function () {
$http.get("http://192.168.1.115:8080/type").then(function(response) {
console.log(response);
console.log(response.data);
return response.data;
});
}
});
... but when I click on the Types tab my data does not display. I looked developer console and I do not even see the GET request kickoff. And my web page looks like this ...
... what am I doing wrong?
There is nothing that calls all_types. Run http.get and assign the response to all_types
app.controller("typeCtrl", function($scope,$http) {
$scope.type_to_look_for = "";
$scope.message = "this is the message. (from typeCtrl)";
$scope.itemsByPage=15;
$http.get("http://192.168.1.115:8080/type").then(function(response) {
$scope.all_types = response;
});
}
});
My understanding is that you want a get request to be fired whenever you click on the Types tab, right? If so, just use ng-click to call your all_types function as follows:
<div ng-controller="typeCtrl" ng-click="all_types()" class="tab-pane" id="types-v" >
Also, you do not need to return response.data in your controller. Just assign the data to a scope object and use it in the template.
And finally, I would suggest wrapping all your ajax calls in factories and then inject those factories in your controllers.
Here is your code
<div ng-controller="typeCtrl" class="tab-pane" id="types-v">
<p>The number {{3 + 4}}.</p>
<p>message is {{message}}</p>
<table st-table="types" class="table table-striped"><!-- Do not need st-safe-src -->
<tbody>
<tr ng-repeat="x in types"><!-- Use the Collection name as types-->
<td>{{x.type}}</td>
</tr>
</tbody>
</table>
</div>
Controller Code
app.controller('typeCtrl', function($scope, $http) {
$scope.type_to_look_for = "";
$scope.message = "this is the message. (from typeCtrl)";
$scope.itemsByPage=15;
$http.get("http://192.168.1.115:8080/type").then(function(response) {
console.log(response.data);
$scope.types = response.data;
});
});
Here is working the plunker

ng-table data not showing on page load

I have integrated ngTable into my mean.io stack and I'm having trouble with populating the table on page load. If I select one of the column headers, the data shows up and the table works as advertised.
Here is my html
<table ng-table="tableParams" class="table">
<tbody ng-repeat="p in $data">
<tr id="tr{{p._id}}" ng-class-odd="'odd'" ng-class-even="'even'">
<td class="rowTd" data-title="'Task Code'" sortable="'task_code'">{{p.task_code}}</td>
<td class="rowTd" data-title="'Task Name'" sortable="'task_name'">{{p.task_name}}</td>
<td class="rowTd" ><input type=button id="editRowBtn{{p._id}}" value="edit"
ng-click="setEditId(p._id)"></td>
</tr>
<tr ng-show="editId===p._id" ng-if="editId===p._id">
<td colspan="7" ng-include src="'editRow.html'"></td>
</tr>
</tbody>
</table>
Here is my controller code.
var data = GeneralTasks.query();
$scope.tableParams = new ngTableParams({
page: 1,
count: 10
},{
total: data.length,
getData: function($defer, params) {
params.total(data.length);
$defer.resolve(data.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});
$scope.editId = -1;
$scope.setEditId = function(pid) {
$scope.editId = pid;
};
I am new to using this table so i'm sure there is something i'm overlooking.
Wanted to provide the answer to my question so it may help others. Anytime an item in the table is added or removed, the table must be reloaded. Since $save and $remove invoke a callback function, just inserted the following for updating the table.
$scope.add = function() {
if (!$scope.tasks) $scope.tasks = [];
var task = new GeneralTasks({
task_code: $scope.task_code,
trade: $scope.trade,
task: $scope.task,
task_name: $scope.task_name
});
task.$save(function(response) {
$scope.tasks.push(response);
var data = $scope.tasks;
$scope.tableParams.total(data.length);
$scope.tableParams.reload();
});
this.task_code = this.trade = this.task = this.task_name = '';
};
First i update the $scope list with the response and then update the tables data and length. Then just call reload.
As I've stated earlier, i do this for $save and $remove. Here is the $remove code.
$scope.remove = function(task) {
for (var i in $scope.tasks) {
if ($scope.tasks[i] === task) {
$scope.tasks.splice(i, 1);
}
}
task.$remove();
var data = $scope.tasks;
$scope.tableParams.total(data.length);
$scope.tableParams.reload();
};
I have noticed that when I edit a name in the list and then cancel, the name does not reset. I suppose I should add similar code for the cancel action but I'm lazy and that's the least of my worries for now. :)
Hope this helps someone else.

Reuse components in AngularJS

As a new AngularJS developer (coming from PHP+Laravel world) I'm facing some troubles designing the architecture of my new app.
Which is the best way to implement a CRUD app where entities are used more than once along the app?
For example: we have the entities 'document' and 'project'. Documents can be listed and viewed alone, but also can be attached to projects. Inside the project detail view I would like to include the attached documents, using the same template used when listing the documents alone. This widget should have its own controller and methods, since its need to make some API calls and apply some business logic; and receive the parent project data in some way.
What should I use for document listing? A directive, a ng-include or some other?
You should use module to use it as reusing component.
https://docs.angularjs.org/guide/module
i'm utilizing angular module and factory like this:
app.js
'use strict';
/* App Module */
var app = angular.module('my-app', [
'my-models',
]);
my-models.js
var myModels = angular.module('my-models', []);
myModels.factory('DocumentsModel', function ($http)
{
var DocumentsModel = function ()
{
};
DocumentsModel.get_documents = function (page, results_per_page)
{
var data = {
page: page,
results_per_page: results_per_page
};
var json = angular.toJson(data);
return $http.post('/api/documents', json);
};
DocumentsModel.set_document_state = function (document_id, document_state_id)
{
var json = angular.toJson(
{
'document_state': document_state_id
}
);
return $http.post('api/document/'+document_id', json);
};
return DocumentsModel;
});
using angular dependency injection mechanism, you can re-use this logic in multiple controllers by adding DocumentsModel to the controller function as parameter:
documents-ctrl.js
var app = angular.module('my-app');
var controller = app.controller("DocumentsCtrl",
function ($scope, DocumentsModel)
{
DocumentsModel.get_documents()
.success(function(data){
$scope.documents = data.documents;
});
});
in addition, you cad define one for your 'project' entity.
Edit:
Javier commented:
assuming your documents response is
[{name: ... , size: ... , last_modified: ... }, {name: ... , size: ... , last_modified: ... }, ...]
you can utilize ng-repeat like this:
<table>
<thead>
<tr>
<th>Name</th>
<th>Size</th>
<th>Last Modified</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="document in documents">
<td>{{ document.name }}</td>
<td>{{ document.size/1024 | number:4 }} MB</td>
<td>{{ document.last_modified | date:'yyyy-MM-dd HH:mm:ss' }}</td>
</tr>
</tbody>
</table>
Just add it as a dependency to your own module. Like
angular.module('test', []);
angular.module('test2', ['test']);
You might want to take a look at Yeoman

ng-repeat ng-click when the click function has already been called earlier in the code

First off, I read the plethora of other questions and answers regarding ng-click, ng-repeat, and child and parent scopes (especially this excellent one.)
I think my problem is new.
I'm trying to call a function using ng-click within a table. The app allows for the sorting of Soundcloud likes. The problem is that when I try to call the ng click function using new data, it still tries to call the function using the old data. Let me explain better with the example:
Controller:
function TopListCtrl($scope, $http) {
$scope.sc_user = 'coolrivers';
$scope.getData = function(sc_user) {
var url = 'http://api.soundcloud.com/users/'+ $scope.sc_user +'/favorites.json?client_id=0553ef1b721e4783feda4f4fe6611d04&limit=200&linked_partitioning=1&callback=JSON_CALLBACK';
$http.jsonp(url).success(function(data) {
$scope.likes = data;
$scope.sortField = 'like.title';
$scope.reverse = true;
});
}
$scope.getData();
$scope.alertme = function(permalink) {
alert(permalink);
};
}
HTML
<div id="topelems">
<p id="nowsorting">Now sorting the Soundcloud likes of <input type=text ng-model="sc_user"><button class="btn-default" ng-click="getData(sc_user);">Sort</button></p>
<p id="search"><input ng-model="query" placeholder="Filter" type="text"/></p>
</div>
<table class="table table-hover table-striped">
<thead>
<tr>
<th>Song</th>
<th>Artist</th>
<th>Likes</th>
<th>Played</th>
<th>Tags</th>
</tr>
</thead>
<tr ng-repeat="like in likes.collection | filter:query | orderBy:sortField:reverse">
<td width="30%"><a href="{{ like.permalink_url }}">{{like.title}}</td>
(Trying to call it here) <td>{{like.user.username}}</td>
<td>{{like.favoritings_count}}</td>
<td>{{like.playback_count}}</td>
<td>{{like.tag_list}}</td>
</tr>
</table>
</div>
</body>
</html>
So I have that function getData. I use it to load the data in using the soundcloud api. I have a form at the top that uses getData to load a new user's Soundcloud data in. I also call the getData function in the controller so that there is an example on the page upon loading.
The problem is when I try to load a new user's data from a <td> I want to be able to click on the user to see and sort their likes.
How do I 'clear' the function or the global namespace (am I even refering to the right thing)? How can I reuse the getData function with a new variable?
Working Jsfiddle for this
In your getData function you have this line:
var url = 'http://api.soundcloud.com/users/'+ $scope.sc_user +'/favorites.json...
but you are passing in the variable sc_user to your getData function and should be using it like this (no $scope):
var url = 'http://api.soundcloud.com/users/'+ sc_user +'/favorites.json...
That being said... your initial data load fails because you are calling:
$scope.getData();
and not:
$scope.getData($scope.sc_user);

Resources