ng table with data from http request - angularjs

Does anyone have a decent example with ng-table loading data upon a success callback from http service?
this.getData = function(){
tmp = this;
tmp.loading = true;
$http.post('/fetch',
$.param({
service_request: JSON.stringify(this.session)
}
)).success(function(data) {
tmp.loading = false;
tmp.tableData = data;
});
};
I would like to build the table from the tableData variable.
Thanks

I think this is one way of doing it.
Create a service to get the table data (I just picked the code from your :
app.factory('getTableData', function($http) {
return {
getData: function(session){
return $http.post('/fetch',
{
service_request: session
}))
}
}
})
Then you inject the service in your controller:
app.controller('DemoCtrl', function(getTableData, $scope, $window) {
$scope.loadTable = function(){
getTableData.getData(JSON.stringify($window.session)) //not sure where you have the session variable stored.
.sucess(function(data){
$scope.tableData = data;
})
.error(function(){
//do something
})
}
})
The HTML should be pretty straightforward:
<button ng-click="loadTable()">Load Table</button>
<table ng-table class="table">
<tr ng-repeat="row in tableData">
<td data-title="'Property1'">{{row.Property1}}</td>
<td data-title="'Property2'">{{row.Property2}}</td>
</tr>
</table>

Related

angularjs object list not binding to ng-repeat

I am using angular 1.5.5 with ui router 0.2.14. I have the view of employee list to be displayed. EmployeeList template is as follows:
<table class="employeeListContainer">
<tr ng-repeat="employee in employees">
<td>
<a ng-bind="employee.EmployeeId" class="employeeId"></a>
<!--ui-sref="employeeDetails{ employeeId: employee.EmployeeId }"-->
</td>
<td ng-bind="employee.FirstName"></td>
<td ng-bind="employee.LastName"></td>
</tr>
<tr>
<td colspan="3" class="paging">
<button ng-disabled="!IsPrevButtonEnabled" ng-click="prevPage()" class="prev-next"><</button>
<span ng-bind="PageNumber"></span>
<button ng-disabled="!IsNextButtonEnabled" ng-click="nextPage()" class="prev-next">></button>
</td>
</tr>
<tr>
<td colspan="3" class="paging">
<span ng-bind="ErrorMessage" ng-show="IsError"></span>
</td>
</tr>
</table>
I have configured the app as follows:
var app = angular.module('app', ['ui.router']);
app.config(function ($urlRouterProvider, $stateProvider, $httpProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider.state('employeeList', {
url: '/List',
templateUrl: '../../Templates/EmployeeList.html',
controller: 'EmployeeListController',
resolve: {
employeeListRs: function (dataService) {
var employeeListRq = getEmployeeListRqInit();
return dataService.callApi('GetEmployees', 'post', [employeeListRq])
.then(function (data) { return data.data; });
},
employeeListRq: function(){
return getEmployeeListRqInit();
},
greeting: function ($q, $timeout) {
var deferred = $q.defer();
$timeout(function () {
deferred.resolve('Hello!');
}, 1000);
return deferred.promise;
}
}
});
$stateProvider.state('default', {
url: '/',
//templateUrl: '../../Templates/EmployeeList.html',
controller: 'defaultController'
});
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
var getEmployeeListRqInit = function () {
return {
PageNumber: 1,
PageSize: 10,
SessionId: "123"
};
}
});
dataService is a service that is wrapper to the original $http.post call. Controller code is as follows:
app.controller('EmployeeListController', function ($scope, employeeListRq, employeeListRs, greeting) {
$scope.PageNumber = employeeListRq.PageNumber;
$scope.PageSize = employeeListRq.PageSize;
$scope.IsError = !employeeListRs.IsSuccess;
$scope.TotalCount = (employeeListRs.EmployeeList == null) ? 0 : employeeListRs.EmployeeList.TotalCount;
$scope.employees = (employeeListRs.EmployeeList == null) ? null : employeeListRs.EmployeeList.Employees;
if ($scope.employees = null) return 1;
var remainder = $scope.TotalCount % $scope.PageSize;
var pageNumber = Math.floor($scope.TotalCount / $scope.PageSize);
var lastPageNumber = remainder > 0 ? pageNumber + 1 : pageNumber;
$scope.IsNextButtonEnabled = $scope.PageNumber != lastPageNumber;
$scope.IsPrevButtonEnabled = $scope.PageNumber != 1;
$scope.IsLoading = false;
$scope.ErrorMessage = employeeListRs.IsSuccess ? '' : employeeListRs.ErrorMessage;
});
I see while debugging in chrome that $scope.employees is set to an array containing 10 objects all with proper fields and values. Also the IsPrevButtonEnabled and IsNextButtonEnabled are set perfectly. The binding is reflected on UI too, perfectly.
But I don't see the table containing employees list. Any suggestions on what I am missing?
Note: I don't get any error on console.
A few things you can try:
(1) Not saying yours is incorrect, but the preferred way to bind the data would be to use expressions. So, instead of this:
<td ng-bind="employee.FirstName"></td>
try this:
<td>{{employee.FirstName}}</td>
(2) This line looks suspicious in your controller:
if ($scope.employees = null) return 1;
It looks like you are assigning a null value to $scope.employees instead of checking for null. I/my teams try to use angular.isDefined($scope.employees) when we want to check for existence.
What are you trying to accomplish with that line?
(3) This looks a little different than how I use services and how I see others use them:
resolve: {
employeeListRs: function (dataService)
It looks to me that employeeListRs returns a promise.
What I typically do is call the service (my angular service which in turn calls the $http service) from inside the controller and then handle the response (both expected and error responses). From there I push the data into the controller's model. I haven't yet mixed service calls into my state machines - I let the controllers make the service calls.
(4) What is inside this css class - employeeListContainer? Could there be something there hiding your table? You might want to share your html and css as well.

How to do $http.get wait response

I have a trouble with $http.get. When my service.js access my MVC Controller, the $http.get don't wait for response. How can I do $http.get wait MVC Controller response? My code.
AngularJS Service:
angular.module("cadastroCliente").factory("clientesAPI", function($http) {
var getClientes = function () {
return $http.get("http://localhost:39732/Cadastro/BuscarClientes/");
};
return {
getClientes: getClientes
};
});
ControllerJS - Edited
angular.module("cadastroCliente").controller("cadastroClienteCtrl", function ($scope, $http, $q, $timeout, clientesAPI) {
$scope.app = "Pesquisar Clientes";
$scope.clientes = [];
var carregarClientes = function () {
clientesAPI.getClientes().success(function (data) {
$scope.clientes = data;
}).error(function (data, status) {
$scope.message = "Aconteceu um problema: " + data;
});
};
carregarClientes();
$scope.totalItems = $scope.clientes.length;
$scope.itemsPerPage = 2;
$scope.currentPage = 1;
$scope.maxSize = 5;
$scope.bigTotalItems = 175;
$scope.bigCurrentPage = 1;
$scope.pageCount = function () {
return Math.ceil($scope.clientes.length / $scope.itemsPerPage);
};
$scope.$watch('currentPage + itemsPerPage', function () {
var begin = (($scope.currentPage - 1) * $scope.itemsPerPage),
end = begin + $scope.itemsPerPage;
$scope.filteredClientes = $scope.clientes.slice(begin, end);
});
});
View:
<div class="table-responsive">
<table class="table table-bordered table-hover table-striped" id="clienteId">
<thead>
<tr>
<th class="col-lg-1">Código</th>
<th class="col-lg-7">Nome</th>
<th class="col-lg-3">Documento</th>
<th class="col-lg-1">Extrato</th>
</tr>
</thead>
<tbody ng-repeat="cliente in filteredClientes">
<tr>
<td>{{cliente.ClienteId}}</td>
<td>{{cliente.Nome}}</td>
<td>{{cliente.CpfCnpj}}</td>
<td style="cursor: pointer"><i class="glyphicon glyphicon-search"></i></td>
</tr>
</tbody>
</table>
</div>
<uib-pagination total-items="totalItems" items-per-page="itemsPerPage" ng-model="currentPage" ng-change="pageChanged()"></uib-pagination>
You can't set $scope.totalItems until the data has arrived which means you need to set it in the success callback where you assign $scope.clientes from the response data.
$http is an ajax request and the first A in ajax is for "asynchronous"
Note that success and error are deprecated and you should be using the recommendation in documentation to use the promise callbacks then() and catch()
I suggest that you put as much logic pertaining to the request in your factory as possible, including handling the response:
var getClientes = function () {
return $http.get("http://localhost:39732/Cadastro/BuscarClientes/")
.then(function(res) {
return res.data
});
};
Also don't forget that the get request returns the response object, and that you might need to return the data property on the response (if that's what you need).
You should also favor the .then() method on promises.
In es6 we can make this very precise and also catch any errors like so:
var getClientes = () => {
return $http.get("http://localhost:39732/Cadastro/BuscarClientes/")
.then(({data}) => data)
.catch(({data}) => console.log(data.message));
};
In your controller we can then do this:
var carregarClientes = function () {
clientesAPI.getClientes()
.then(function (data) {
$scope.clientes = data;
})
};
In es6:
var carregarClientes = () => {
clientesAPI.getClientes()
.then(data => $scope.clientes = data);
};
EDIT: Response to update code in OP
Unfortunately, anything pertaining to clientes should be done in the callback of the request:
var carregarClientes = function () {
clientesAPI.getClientes()
.then(function (data) {
$scope.clientes = data;
//Assign any other variables
})
};
The reason being, is that all your code in the controller referencing clientes is referencing the original empty array and not the data from the request. This is because it's outside of the call. Therefore, that code is run while the request is being made. If you place it inside the callback it has access to the returned data once it arrives.

angularjs not updaing propeties when promises used

I am using service to get JSON object using promises. It is then converted into array and assign to a property which is in $scope object. The problem is that array is not getting updated or any properties inside promise then() method.
Controller
var searchController = function ($scope, $SPJSOMService) {
$scope.myName = "old name";
$scope.getUsers = function ($event) { //called on button click
$event.preventDefault();
var queryText = "test user";
$SPJSOMService.getUsers(queryText)
.then(function myfunction(users) {
$scope.userCollection = JSON.parse(JSON.stringify(users)).d.results;
// $scope.$apply(); this line throwing error. $rootScope in progress
$scope.myName = "new name"; //not getting updated
}, function (reason) {
alert(reason);
});
};
};
Service
var SPJSOMService = function ($q, $http, $rootScope) {
this.getUsers = function (userToSerach) {
var deferred = $q.defer();
$http({
url:'some url',
method: "GET",
headers: {
"accept": "application/json;odata=verbose",
"content-Type": "application/json;odata=verbose"
}
})
.success(function (data, status, headers, config) {
deferred.resolve(data); //successfully return data
})
.error(function (data, status, headers, config) {
deferred.reject(data);
});
return deferred.promise;
};
};
Updated
index.html
<div ng-include="'Search.html'">
</div>
<div ng-include="'searchResults.html'"></div>
search.html
<div id="containerDiv" ng-controller="searchController as search">
<input class="button" type="button" ng-click="getUsers($event);" value="Search" id="btnSearch" />
</div>
searchResults.html
<div ng-controller="searchResultController as result">
<table >
<thead>
<tr>
<th>Name</th>
<th>EMail</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in userCollection">
<td>{{$index}} {{item.userName}}</td>
<td>{{$index}} {{item.userEmail}}</td>
</tr>
</tbody>
</table>
</div>
So search.html returns the data by calling the service and I am trying to pass it to the page namely searchResults.html which have its own controller.
$scope.users = $scope.userCollection;
Service class correctly returning data, but the problem is inside then(), which is not updating $scope.userCollection, hence UI is not getting updated.
Please help me out, what am I missing here.
In angular controllers can bind to the view in two ways:
"controller as"
through scope
It looks you are using the "controller as" flavor here...
<div ng-controller="searchResultController as result">
Refer to https://docs.angularjs.org/api/ng/directive/ngController for more information.
Change your controller code to:
var searchController = function ($scope, $SPJSOMService) {
//note use of "this" instead of "$Scope"
var _this = this;
_this.myName = "old name";
_this.getUsers = function ($event) { //called on button click
$event.preventDefault();
var queryText = "test user";
$SPJSOMService.getUsers(queryText)
.then(function myfunction(users) {
_this.userCollection = users.d.results; //You don't need JSON.parse not JSON.stringify
_this.myName = "new name";
}, function (reason) {
alert(reason);
});
};
};
and in your view use the controller "alias":
<div ng-controller="searchResultController as result">
...
<tr ng-repeat="item in result.userCollection">
...
You have to push it to the new array I think. Have you tried this in your then statement?
$scope.myName.push("new name");
It should put it in the existing array. Let me know if it works.

AngularJS with MongoDB, data is pulled from database, but cannot display with ng-repeat

I am trying to get data from the DB and display it using ng-repeat. The getAll function from the factory does the job properly, I get an object with all the data, but it is not displayed properly. In the table I only get the first index, with nothing after it.
If i try with for(i = 0 ; i < DataService.persons.length ; i++), it works fine, but I cannot use it with ng-repeat.
var testReactie = angular.module('testReactie', ['ngRoute']);
testReactie.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl : 'instructiuni.ejs'
})
.when('/form', {
templateUrl : 'form.ejs',
controller : 'formContr'
})
.when('/test', {
templateUrl : 'joc.ejs',
controller : 'gameContr'
})
.when('/stat', {
templateUrl : 'scoruri.ejs',
controller : 'statContr',
resolve: {
postPromise:['DataService', function(DataService){
return DataService.getAll();
}]
}
});
});
testReactie.factory('DataService', ['$http', function($http) {
var o = {
persons:[],
person:{}
};
o.getAll = function(){
return $http.get('/db').success(function(data){
o.persons = data;
});
};
o.create = function() {
return $http.post('/db', o.person).success(function(data){
o.persons.push(data);
});
};
return o;
}]);
testReactie.controller('mainContr',function($scope) {
});
testReactie.controller('statContr',function($scope, DataService) {
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<h2>Scoruri</h2>
<table class="table">
<thead>
<tr>
<th>Nr.</th>
<th>Sex</th>
<th>Varsta</th>
<th>Timp Mediu</th>
</tr>
</thead>
<tbody>
<div ng-repeat = "pers in DataService.persons">
<tr>
<td>{{$index + 1}}</td>
<td>{{pers.sex}}</td>
<td>{{pers.varsta}}</td>
<td>{{pers.timp}}</td>
</tr>
</div>
</tbody>
</table>
</div>
You cannot run a factory as a controller
In your controller do something like
testReactie.controller('mainContr', ['DataService', '$scope', function(DataService, $scope) {
DataService.getAll().then(function(successData){ // a promise helps you do something when it's resolved
$scope.awesomeData = successData;
}
});
Change your factory's get all to be something like
o.getAll = function(){
var promise = $q.defer(); // the $q helps create a promise
return $http.get('/db').success(function(data){
promise.resolve(data); // promise returns data when resolved
});
return promise; // returns a promise
};
your template should be
<div ng-repeat = "pers in awesomeData">
This is because when you have it in your template, it will automatically call $scope.awesomeData. So when you had DataService then it was calling $scope.DataService which was undefined.
I hope this helps.
I fixed the problem. It was from the HTML. I added the ng-repeat directive in a div and it broke the table. After deleting the div and adding the directive in the tag, it worked fine.

why is this resource not updating the view after using $delete method

In my angular app I have a controller as follows:
function TemplateListControl($scope, TemplateService){
$scope.templates = TemplateService.get(); // Get objects from resource
// Delete Method
$scope.deleteTemplate = function(id){
$scope.templates.$delete({id: id});
}
}
Within the view I have a table thats bound to templates model. as follows:
<table ng-model="templates">
<thead>
<tr>
<th style="width:40%">Title</th>
<th style="width:40%">controls</th>
</tr>
<thead>
<tbody>
<tr ng-repeat="template in templates">
<td>
<!-- Link to template details page -->
<a href="#/template/[[template.id]]">
[[template.title]]
</a>
</td>
<td>
<!-- Link to template details page -->
<a class="btn btn-primary btn-small"
href="#/template/[[template.id]]">Edit
</a>
<!-- Link to delete this template -->
<a class="btn btn-primary btn-small"
ng-click="deleteTemplate(template.id)">Delete
</a>
</td>
</tr>
</tbody>
</table>
Now when I click on the delete link in the above template, It calls the deleteTemplate method and a successful DELETE call is made to the REST api. But the view does not get updated until it is refreshed and $scope.templates = TemplateService.get(); is initiated again. What am I doing wrong?
I prefer using promises instead of callback. Promises are the new way to handle asynchronous processes. You can inspect the result using a a promise right after it came back from the server.
//Controller
myApp.controller('MyController',
function MyController($scope, $log, myDataService) {
$scope.entities = myDataService.getAll();
$scope.removeEntity = function (entity) {
var promise = myDataService.deleteEntity(entity.id);
promise.then(
// success
function (response) {
$log.info(response);
if (response.status == true) {
$scope.entities.pop(entity);
}
},
// fail
function (response) {
$log.info(response);
// other logic goes here
}
);
};
});
//DataService
myApp.factory('myDataService', function ($log, $q, $resource) {
return {
getAll: function () {
var deferred = $q.defer();
$resource('/api/EntityController').query(
function (meetings) {
deferred.resolve(meetings);
},
function (response) {
deferred.reject(response);
});
return deferred.promise;
},
deleteEntity: function (entityId) {
var deferred = $q.defer();
$resource('/api/EntityController').delete({ id: entityId},
function (response) {
deferred.resolve(response);
},
function (response) {
deferred.reject(response);
});
return deferred.promise;
}
};
});
//Web API Controller
public class MeetingController : BaseApiController
{
// .... code omited
public OperationStatus Delete(int entityId)
{
return _repository.Delete(_repository.Single<MyEntity>(e => e.EntityID == entityId));
}
}
Note: $log, $q, $resource are built in services. Hope it helps :)
You also have to update client side so modify your source code as below
ng-click="deleteTemplate($index)">
$scope.delete = function ( idx ) {
var templateid = $scope.templates[idx];
API.Deletetemplate({ id: templateid.id }, function (success) {
$scope.templates.splice(idx, 1);
});
};
You could pass a callback function to $resource.$delete
function TemplateListControl($scope, TemplateService){
$scope.templates = TemplateService.get(); // Get objects from resource
// Delete Method
$scope.deleteTemplate = function(id){
TemplateService.$delete({id: id}, function(data) {
$scope.templates = data;
});
}
}
Attention
If your REST APIs delete function returns an array you have to set isArray: true in your Angular $resource to avoid a AngularJS $resource error - TypeError: Object # has no method 'push'
$resource(URL, {}, {
delete: {method:'DELETE', isArray: true}
});

Resources