How to Paginate dynamic AngularJS table? - javascript

How do I get pagination with ng-table-dynamic and $http working?
HTML specification of the table is
<table class="table-bonds table table-bordered table-hover table-striped"
export-csv="csv"
separator=","
show-filter="true"
ng-table-dynamic="bondsTable.bondsDataParams with bondsTable.bondsDataCols">
<tr ng-repeat="row in $data">
<td class="hand"
ng-repeat="col in $columns">{{::row.node[col.field]}}</td>
</tr>
The table creation code is:
self.bondsDataParams = new NgTableParams({
page: 1, // show first page
count: 5 // count per page
}, {
filterDelay: 0,
total: 0,
getData: function (params) {
return $http(bondsDataRemote).then(function successCallback(response) {
// http://codepen.io/christianacca/pen/mJoGPE for total setting example.
params.total(response.data.nodes.length);
return response.data.nodes;
}, function errorCallback(response) {
});
}
});
AngularJS 1.5.8

This is an excellent directive for pagination have a look at it . It has lots of options and its easy to use.

The main problem was mixing up loading the data via ajax and not supporting the filtering/pagination on the server side of the request.
Either provide all the data up-front so that the table can filter, or fully support the pagination, sorting and filtering on the server side.
Option 1. Load the data before hand. I used this option because my dataset is not that big and it seemed like the easiest way to allow people to use all the permutations of filtering sorting and downloading.
No total value is required here. The data is all loaded.
var Api = $resource('/green-bonds.json');
// Or just load all the data at once to enable in-page filtering, sorting & downloading.
Api.get({page: "1", count: "10000"}).$promise.then(function (data) {
self.bondsDataParams = new NgTableParams({count: 25}, {
dataset: data.results
})
});
Or fully support the lazy loading data API and set total. Uses getData: rather than just setting dataset.
var Api = $resource('/green-bonds.json');
this.bondsDataParams = new NgTableParams({}, {
getData: function (params) {
return Api.get(params.url()).$promise.then(function (data) {
params.total(data.count);
return data.results;
});
}
});
Note 1: By default $resource expects an object .get() for object, .query() for array. Also see isArray:. I didn't get this to work.
Note 2: params.url() provides $resource with the ng-table params. e.g. {page: "1", count: "10"}

Related

How to update JQuery DataTables from Ajax Call [duplicate]

I am using plugin jQuery datatables and load my data which I have loaded in DOM at the bottom of page and initiates plugin in this way:
var myData = [
{
"id": 1,
"first_name": "John",
"last_name": "Doe"
}
];
$('#table').dataTable({
data: myData
columns: [
{ data: 'id' },
{ data: 'first_name' },
{ data: 'last_name' }
]
});
Now. after performing some action I want to get new data using ajax (but not ajax option build in datatables - don't get me wrong!) and update the table with these data. How can i do that using datatables API? The documentation is very confusing and I can not find a solution. Any help will be very much appreciated. Thanks.
SOLUTION: (Notice: this solution is for datatables version 1.10.4 (at the moment) not legacy version).
CLARIFICATION Per the API documentation (1.10.15), the API can be accessed three ways:
The modern definition of DataTables (upper camel case):
var datatable = $( selector ).DataTable();
The legacy definition of DataTables (lower camel case):
var datatable = $( selector ).dataTable().api();
Using the new syntax.
var datatable = new $.fn.dataTable.Api( selector );
Then load the data like so:
$.get('myUrl', function(newDataArray) {
datatable.clear();
datatable.rows.add(newDataArray);
datatable.draw();
});
Use draw(false) to stay on the same page after the data update.
API references:
https://datatables.net/reference/api/clear()
https://datatables.net/reference/api/rows.add()
https://datatables.net/reference/api/draw()
You can use:
$('#table').dataTable().fnClearTable();
$('#table').dataTable().fnAddData(myData2);
Jsfiddle
Update. And yes current documentation is not so good but if you are okay using older versions you can refer legacy documentation.
You need to destroy old data-table instance and then re-initialize data-table
First Check if data-table instance exist by using $.fn.dataTable.isDataTable
if exist then destroy it and then create new instance like this
if ($.fn.dataTable.isDataTable('#dataTableExample')) {
$('#dataTableExample').DataTable().destroy();
}
$('#dataTableExample').DataTable({
responsive: true,
destroy: true
});
Here is solution for legacy datatable 1.9.4
var myData = [
{
"id": 1,
"first_name": "Andy",
"last_name": "Anderson"
}
];
var myData2 = [
{
"id": 2,
"first_name": "Bob",
"last_name": "Benson"
}
];
$('#table').dataTable({
// data: myData,
aoColumns: [
{ mData: 'id' },
{ mData: 'first_name' },
{ mData: 'last_name' }
]
});
$('#table').dataTable().fnClearTable();
$('#table').dataTable().fnAddData(myData2);
In my case, I am not using the built in ajax api to feed Json to the table (this is due to some formatting that was rather difficult to implement inside the datatable's render callback).
My solution was to create the variable in the outer scope of the onload functions and the function that handles the data refresh (var table = null, for example).
Then I instantiate my table in the on load method
$(function () {
//.... some code here
table = $("#detailReportTable").DataTable();
.... more code here
});
and finally, in the function that handles the refresh, i invoke the clear() and destroy() method, fetch the data into the html table, and re-instantiate the datatable, as such:
function getOrderDetail() {
table.clear();
table.destroy();
...
$.ajax({
//.....api call here
});
....
table = $("#detailReportTable").DataTable();
}
I hope someone finds this useful!

Dynamically compiling and mounting elements with VueJS

The Issue
I've created a light-weight wrapper around jQuery DataTables for VueJS like so:
<template>
<table ref="table" class="display table table-striped" cellspacing="0" width="100%">
<thead>
<tr>
<th v-for="(column, index) in columns">
{{ column.name }}
</th>
</tr>
</thead>
</table>
</template>
<script>
export default {
props: ['columns', 'url'],
mounted: function () {
$(this.$refs.table).dataTable({
ajax: this.url,
columns: this.columns
});
// Add any elements created by DataTable
this.$compile(this.$refs.table);
}
}
</script>
I'm utilizing the data table like so:
<data-table
:columns="
[
{
name: 'County',
data: 'location.county',
},
{
name: 'Acres',
data: 'details.lot_size',
},
{
name: 'Price',
data: 'details.price',
className: 'text-xs-right',
},
{
name: 'Actions',
data: null,
render: (row) => {
return "\
<a #click='editProperty' class='btn btn-warning'><i class='fa fa-pencil'></i> Edit</a>\
";
}
},
]
"
url="/api/properties"
></data-table>
Note the "render" method for the Actions column. This function runs just fine and renders the button as expected, however the #click handler is not functional.
Looking around I've found two links which were not helpful:
Issue 254 on the VueJS GitHub repo provides a solution for VueJS 1.0 (using this.$compile) however this was removed in VueJS 2.0
A blog post by Will Vincent discusses how to make the DataTable re-render when local data changes dynamically, but doesn't provide a solution for attaching handlers to the rendered elements
Minimum Viable Solution
If the rendered element can't be compiled and mounted, that would alright so long as I could run methods of the DataTable component on-click. Perhaps something like:
render: (row) => {
return "\
<a onclick='Vue.$refs.MyComponent.methods.whatever();' />\
";
}
Is there any such way to call methods from outside of the Vue context?
This meets your minimum viable solution.
In your columns definition:
render: function(data, type, row, meta) {
return `<span class="edit-placeholder">Edit</span>`
}
And in your DataTable component:
methods:{
editProperty(data){
console.log(data)
}
},
mounted: function() {
const table = $(this.$refs.table).dataTable({
ajax: this.url,
columns: this.columns
});
const self = this
$('tbody', this.$refs.table).on( 'click', '.edit-placeholder', function(){
const cell = table.api().cell( $(this).closest("td") );
self.editProperty(cell.data())
});
}
Example (uses a different API, but the same idea).
This is using jQuery, but you're already using jQuery so it doesn't feel that terrible.
I played some games trying to get a component to mount in the render function of the data table with some success, but I'm not familiar enough with the DataTable API to make it work completely. The biggest issue was the DataTable API expects the render function to return a string, which is... limiting. The API also very irritatingly doesn't give you a reference to the cell you are currently in, which seems obvious. Otherwise you could do something like
render(columnData){
const container = document.createElement("div")
new EditComponent({data: {columnData}).$mount(container)
return container
}
Also, the render function is called with multiple modes. I was able to render a component into the cell, but had to play a lot of games with the mode, etc. This is an attempt, but it has several issues. I'm linking it to give you an idea what I was trying. Maybe you will have more success.
Finally, you can mount a component onto a placeholder rendered by DataTable. Consider this component.
const Edit = Vue.extend({
template: `<a #click='editProperty' class='btn btn-warning'><i class='fa fa-pencil'></i> Edit</a>`,
methods:{
editProperty(){
console.log(this.data.name)
this.$emit("edit-property")
}
}
});
In your mounted method you could do this:
mounted: function() {
const table = $(this.$refs.table).dataTable({
ajax: this.url,
columns: this.columns
});
table.on("draw.dt", function(){
$(".edit-placeholder").each(function(i, el){
const data = table.api().cell( $(this).closest("td") ).data();
new Edit({data:{data}}).$mount(el)
})
})
}
This will render a Vue on top of each placeholder, and re-render it when it is drawn. Here is an example of that.

AngularJS UI-GRID: editDropdownOptionsFunction and async $http.get

I use ui-grid v3.2.9. I have grid with inline editing, one of editing cell - dropdown control. I want to get array for dropdown control every time when I click to this cells. I try to use editDropdownOptionsFunction to download json for dropdown:
columnDefs: [
{
name: 'serial',
displayName: 'Serial',
width: 100,
enableCellEdit: true,
editableCellTemplate: 'ui-grid/dropdownEditor',
editDropdownIdLabel: 'id',
editDropdownValueLabel: 'id',
editDropdownOptionsFunction: function(rowEntity, colDef){
var res = [];
$http.get('index.php?r=docs/serialsjson2&recid=' + rowEntity.id)
.success(function (data) {
res = data;
});
return res;
}
},
],
But as I understand $http.get finished too late and no fills dropdownarray.
Help me please. How do I need to do request data from server to dropdown widget in moment click?
Loading the dropdown data happens after the data is returned into success function.Only means to get the data faster is retriving data in simple steps without more loops or query operations[re-factor].
If that doesn't happen you can just try adding spinner(loader) in http interceptor and disable dropdown untill data is populated.
There are lot of ways in implementing spinners and hideoverlays for dropdown.
Below is one example link
Spinner and Overlay
you need to return the promise from $http:
return $http.get('index.php?r=docs/serialsjson2&recid=' + rowEntity.id).then(function (data) {
return data;
});
Also use .then instead of .success----success is deprecated

Using Select 2 with ASP.NET MVC

I am working on an ASP.NET MVC 4 app. In my app, I'm trying to replace my drop down lists with the Select 2 plugin. Currently, I'm having problems loading data from my ASP.NET MVC controller. My controller looks like this:
public class MyController : System.Web.Http.ApiController
{
[ResponseType(typeof(IEnumerable<MyItem>))]
public IHttpActionResult Get(string startsWith)
{
IEnumerable<MyItem> results = MyItem.LoadAll();
List<MyItem> temp = results.ToList<MyItem>();
var filtered = temp.Where(r => r.Name.ToLower().StartsWith(startsWith.ToLower());
return Ok(filtered);
}
}
When I set a breakpoint in this code, I notice that startsWith does not have a value The fact that the breakpoint is being hit means (I think) my url property below is set correct. However, I'm not sure why startsWith is not set. I'm calling it from Select 2 using the following JavaScript:
function formatItem(item) {
console.log(item);
}
function formatSelectedItem(item) {
console.log(item);
}
$('#mySelect').select2({
placeholder: 'Search for an item',
minimumInputLength: 3,
ajax: {
url: '/api/my',
dataType: 'jsonp',
quietMillis: 150,
data: function (term, page) {
return {
startsWith: term
};
},
results: function (data, page) {
return { results: data };
}
},
formatResult: formatItem,
formatSelection: formatSelectedItem
});
When this code runs, the only thing I see in the select 2 drop down list is Loading failed. However, I know my api is getting called. I can see in fiddler that a 200 is coming back. I can even see the JSON results, which look like this:
[
{"Id":1,"TypeId":2,"Name":"Test", "CreatedOn":"2013-07-20T15:10:31.67","CreatedBy":1},{"Id":2,"TypeId":2,"Name":"Another Item","CreatedOn":"2013-07-21T16:10:31.67","CreatedBy":1}
]
I do not understand why this isn't working.
From the documentation:
Select2 provides some shortcuts that make it easy to access local data
stored in an array...
... such an array must have "id" and "text" keys.
Your json object does not contain "id" or "text" keys :) This should work though i have not tested it:
results: function (data, page) {
return { results: data, id: 'Id', text: 'Name' }
}
There's further documentation following the link on alternative key binding... I believe thats where your problem lies.
Hopefully this helps.

Can we set multiple values to modle in backbone

I am new to backbone and nodejs, I have made a demo which used backbone and nodejs for updating and inserting data. I'm able to send put request with single data at a time.
this.model.set({
user_id:Session.get('userid'),
seat_id:seatId
});
this.model.save({
success: function() {
// do some stuff here
alert("a")
},
error: function() {
// do other stuff here
alert("b")
}
})
The above code post single row info to server. I want to send multiple info to server at a time. Can we set model something like below
this.model.set([{
user_id:Session.get('userid'),
seat_id:2
},{
user_id:Session.get('userid'),
seat_id:3
}]);
Thanks
You can do that:
arr = [{
user_id:Session.get('userid'),
seat_id:2
},{
user_id:Session.get('userid'),
seat_id:3
}];
this.model.set(sessions, arr);

Categories

Resources