Using the ag-grid table i'm trying to use cellRender to route an entire table row to the right page. It's a bit unclear how to to this with nuxt-link.
The path the ag-grid row(cell) should link to is the following:
<nuxt-link :to="'users/' + id + '/overview' ">
For now I created a cellRender with the route name based on the info I found so far.
this.columnDefs = [
{
headerName: "ID",
field: "id",
cellRenderer: params => {
const route = {
name: "users", // This path should redirect to <nuxt-link :to="'users/' + id + '/overview' ">
params: { id: params.value }
};
const link = document.createElement("a");
link.href = this.$router.resolve(route).href;
link.innerText = params.value;
link.addEventListener("click", e => {
e.preventDefault();
this.$router.push(route);
});
return link;
}
},
{
headerName: "Naam",
field: "naam",
checkboxSelection: true,
sortable: true,
headerCheckboxSelection: true
},
{ headerName: "Type", field: "type", sortable: true },
{ headerName: "Status", field: "status", sortable: true },
{ headerName: "Laatste Contact", field: "contact", sortable: true },
];
What would be the best way to implement these kind of links for an entire row?
Thanks in advance!
In this case, we can just simulate the HTML as nuxt-link does:
cellRenderer: (params) => {
return `${params.value}`;
}
With the we don't need to care about adding history to the route, the "bad" thing it's if you change this route you need also to update here.
I was able to programmaticly link to another page while clicking a row. But the parameters are still visible in my link in the browser.
What I did:
this.gridOptions.onRowClicked = params => {
this.$router.push({
path: "/users/${params.data.id}/overview"
});
};
This gives me the following url in the browser
users/$%7Bparams.data.id%7D/overview
Related
I have a vuetify table. Right now, I call API for all records and load all records into my table. I might not see the performance differences now because it's less than 1000. When I have 10,000,000 this might not work anymore. I need to only query for the first 10 on page loads, and my BE API already supports that. Then, I will make calls to API to get the next/previous 10 only when the user clicked on the pagination buttons.
data() {
return {
headers: [
{
text: 'Name',
align: 'start',
sortable: false,
value: 'name',
width: '20%'
},
{ text: 'Link Count', value: 'count', width: '10%' },
{ text: 'URL', value: 'details', width: '50%' },
{ text: 'Actions', value: 'id', width: '20%' }
],
items: []
}
},
and I set this.items to the response from API below :
axios.defaults.headers['Content-Type'] = 'application/json'
axios
.post(window.MTS_URL, vc_url_group)
.then((response) => {
this.items = response.data.groups
})
Can someone please get me started?
It's highly depends on your backend implementation, but there are some common points:
You should define v-data-table this way:
<v-data-table
:headers="headers"
:items="desserts"
:items-per-page="10"
:server-items-length="totalDesserts"
:options.sync="options"
></v-data-table>
So you need to operate with three variables:
desserts as a [1..10] rows on your current page,
totalDesserts as a total amount of rows (10,000,000 in your case)
options as a synchronize point of your pagination
These variables comes from an example of official docs.
After that, in order to track user click on pagination buttons, you need to define a deep watcher (it should be deep in order to react to changes in nested props):
watch: {
options: {
handler() {
this.getDessertsFromApi();
},
deep: true
},
},
And then - your API call method:
methods: {
async getDessertsFromApi() {
this.loading = true;
const { sortBy, sortDesc, page, itemsPerPage } = this.options;
// Your axios call should be placed instead
await this.simulateApiCall({
size: itemsPerPage,
page: page - 1,
})
.then((response) => {
this.desserts = response.data.content;
this.totalDesserts = response.data.totalElements;
})
.finally(() => {
this.loading = false;
});
},
}
Test this at CodePen with simulated API calls.
I'm using bootstrap-vue with version 2.9.0. When navigating to another page, the result does not display unless I click on to another page then the previous page will show up then immediately show the current page, which I find it really weird.
Here's a snippet:
<b-table
:items="dataTable.customerList"
:fields="dataTable.fields"
:per-page="dataTable.perPage"
:current-page="dataTable.currentPage"
:sort-by.sync="dataTable.sortBy"
:sort-desc.sync="dataTable.sortDesc"
:no-local-sorting="true"
#sort-changed="sortingChanged"
responsive
striped
hover
show-empty
empty-text="Loading..."
id="tbl-customer-list"
busy.sync="true"
>
</b-table>
<b-pagination
v-model="dataTable.currentPage"
:total-rows="dataTable.totalRows"
:per-page="dataTable.perPage"
#input="getCustomers(dataTable.currentPage)"></b-pagination>
And the JS:
export default {
page: {
title: 'Customers',
meta: [{ name: 'description', content: appConfig.description }],
},
components: {
Layout,
PageHeader,
},
methods: {
getCustomers(currentPage) {
this.busy = true;
customerList({page: currentPage}).then((response) => {
this.dataTable.customerList = response.data;
this.dataTable.totalRows = response.total;
this.dataTable.currentPage = response.current_page;
this.dataTable.perPage = response.per_page;
this.dataTable.lastPage = response.last_page;
this.busy = false;
})
},
sortingChanged(ctx) {
console.log(ctx);
this.$root.$emit('bv::table::refresh', 'tbl-customer-list')
},
},
mounted() {
this.getCustomers();
},
data() {
return {
title: 'Customers',
busy: false,
dataTable: {
customerList: [],
fields: [
{ key: 'customer_name', label: 'Full Name', sortable: true },
{ key: 'actions', sortable: false },
],
totalRows: 0,
currentPage: 1,
perPage: 0,
lastPage: 1,
sortBy: 'first_name',
sortDesc: false,
filter: null,
filterOn: [],
},
}
},
}
When I remove :current-page="dataTable.currentPage" on the b-table, it works fine but I when clicking on the row headers will always display the current page as 1. (See sortingChanged)
I'm new in DataTables and I have a simple datatable for which I'm trying to add a Font Awesome fa-info-circle image instead of one column header by using render like:
table = $("#datatable-buttons").DataTable({
data: document.pvm.tableContent(),
columns: [
{ data: "Info", render: function (data, type, full, meta) { if (type === 'display') return '<span style="font-size:75%" class="fa fa-info-circle"></span>' } },
{ data: "WiFi", title: "WiFi" },
{ data: "GPS", title: "GPS" },
],
fixedHeader: true,
dom: "lfBrtip",
buttons: [
{
extend: "copy",
className: "btn-sm"
},
{
extend: "csv",
className: "btn-sm",
filename: "DeviceMnag"
},
{
extend: "excel",
className: "btn-sm",
filename: "DeviceMnag"
},
{
extend: "pdfHtml5",
className: "btn-sm",
filename: "DeviceMnag"
},
{
extend: "print",
className: "btn-sm"
},
],
});
But it seems that my icon instead of being just in the header for Info column, there is no icon in the header but in the data columns instead of the correct data. Is is possible to add a icon just for one field in the header?
I believe when you are saying "column header" you mean the title? render() is for rendering column data, you set the column header through the title property :
var table = $('#example').DataTable({
columnDefs: [{
targets: 0,
data: '0', //just use DOM
title: '<i class="fa fa-info-circle fa-lg"></i>'
}]
})
demo -> http://jsfiddle.net/6kp3tvpb/
title can be a function as well :
title: function() {
return '<i class="fa fa-info-circle fa-lg"></i>'
}
But notice that this callback only is called once.
i have a grid developed using kendo ui and asp.net mvc4 razor.in there i have used the html syntax for kendo grid instead of asp.net mvc.
this is the code of my grid
<div id="example" class="k-content">
<div id="batchgrid">
</div>
</div>
<script type="text/javascript" lang="javascript">
$("#batchGrid").click(function () {
var crudServiceBaseUrl = "http://demos.kendoui.com/service",
dataSource = new kendo.data.DataSource({
transport: {
read: {
url: crudServiceBaseUrl + "/Products",
dataType: "jsonp"
},
update: {
url: crudServiceBaseUrl + "/Products/Update",
dataType: "jsonp"
},
destroy: {
url: crudServiceBaseUrl + "/Products/Destroy",
dataType: "jsonp"
},
create: {
url: crudServiceBaseUrl + "/Products/Create",
dataType: "jsonp"
},
parameterMap: function (options, operation) {
if (operation !== "read" && options.models) {
return { models: kendo.stringify(options.models) };
}
}
},
batch: true,
pageSize: 20,
schema: {
model: {
id: "ProductID",
fields: {
ProductID: { editable: false, nullable: true },
ProductName: { validation: { required: true} },
UnitPrice: { type: "number", validation: { required: true, min: 1} },
UnitsInStock: { type: "number", validation: { min: 0, required: true} },
Discontinued: { type: "boolean" },
TotalStock: { type: "number" }
}
}
},
// group: {
// field: "UnitPrice", aggregates: [
// { field: "UnitPrice", aggregate: "sum" },
// { field: "TotalStock", aggregate: "sum" }
// ]
// },
aggregate: [{ field: "TotalStock", aggregate: "sum"}]
});
$("#batchgrid").kendoGrid({
dataSource: dataSource,
dataBound: onDataBound,
navigatable: true,
filterable: {
messages: {
and: "And",
or: "Or",
filter: "Apply filter",
clear: "Clear filter",
info: "Filter by"
},
extra: false, //do not show extra filters
operators: { // redefine the string operators
string: {
contains: "Contains",
doesnotcontain: "Doesn't contain",
startswith: "Starts With",
endswith: "Ends"
},
number: {
eq: "Is Equal To",
neq: "Not equal to",
gte: "Greater than or equal to",
lte: "Less than or equal to",
gt: "Greater than",
lt: "Less than"
}
}
},
reorderable: true, //not working
selectable: "multiple",
pageable: {
refresh: true,
pageSizes: [5, 10, 20, 50, 100]
},
height: 430,
width: 300,
toolbar: [
{
name: "my-create",
text: "Add new record"
},
{
name: "save",
text: "save changes"
},
{
name: "cancel",
text: "cancel changes"
},
{
name: "export",
text: "Export To Excel"
}
],
columns: [
// { field: "ProductID", title: "No", width: "90px" },
{title: "No", template: "#= ++record #", width: 45 },
{ field: "ProductName", title: "Product Name", width: "350px" },
{ field: "UnitPrice", title: "Unit Price", format: "{0:c}", width: "130px" },
{ field: "UnitsInStock", title: "Units In Stock", width: "150px" },
{ field: "Discontinued", title: "Purchase", width: "110px" },
{ field: "TotalStock", title: "Total Stock", width: "150px", footerTemplate: "Total : #= kendo.toString(sum, 'C') #", format: "{0:c2}" }
//{ command: ["destroy"], title: " ", width: "175px" }
],
export: {
cssClass: "k-grid-export-image",
title: "people",
createUrl: "/Home/ExportToExcel",
downloadUrl: "/Home/GetExcelFile"
},
groupable: {
messages: {
empty: "Drop columns here"
}
}, //not working
columnMenu: {
sortable: true,
filterable: true,
messages: {
columns: "Hide/Show Columns",
filter: "Apply filter",
sortAscending: "Sort (asc)",
sortDescending: "Sort (desc)"
}
},
resizable: true,
dataBinding: function () {
record = (this.dataSource.page() - 1) * this.dataSource.pageSize();
},
sortable: {
mode: "multiple"
},
sort: { field: "ProductID", dir: "asc" },
editable: { mode: "incell", createAt: "bottom" }
});
//custom global variables
newRowAdded = false;
checkedOnce = false;
var grid = $("#batchgrid").data("kendoGrid");
$(".k-grid-my-create", grid.element).on("click", function (e) {
window.newRowAdded = true;
var dataSource = grid.dataSource;
var total = dataSource.data().length;
dataSource.insert(total, {});
dataSource.page(dataSource.totalPages());
grid.editRow(grid.tbody.children().last());
});
grid.bind("saveChanges", function () {
window.newRowAdded = false;
// var grid = $("#batchgrid").data("kendoGrid");
// grid.dataSource.sort({ field: "ProductID", dir: "asc" });
// GetValOf();
// var grid = $('#batchgrid').data("kendoGrid");
// var total = 0;
// $.each(grid.dataSource.view(), function () {
// total += this.TotalStock;
// });
// alert(total);
});
grid.bind("cancelChanges", function () {
window.newRowAdded = false;
});
$(".k-grid-export", "#batchgrid").bind("click", function (ev) {
// your code
// alert("Hello");
var grid = $("#batchgrid").data("kendoGrid");
grid.dataSource.pageSize(parseInt($("#batchgrid").data("kendoGrid").dataSource.data().length));
excelImport();
});
});
</script>
but i got some example code for importing grid data to excel and in there they used asp.net mvc syntax.
here is the code.
#(
Html.Kendo().Grid(Model).Name("Grid")
.DataSource(ds => ds.Ajax()
.Model(m =>
{
m.Id(p=>p.ProductID);
})
.Read(r => r.Action("Read", "Home"))
)
.ToolBar(toolBar =>
toolBar.Custom()
.Text("Export To Excel")
.HtmlAttributes(new { id = "export" })
.Url(Url.Action("Export", "Home", new { page = 1, pageSize = "~", filter = "~", sort = "~" }))
)
.Columns(columns =>
{
columns.Bound(p => p.ProductID);
columns.Bound(p => p.ProductName);
columns.Bound(p => p.UnitPrice).Format("{0:c}");
columns.Bound(p => p.QuantityPerUnit);
})
.Events(ev => ev.DataBound("onDataBound"))
.Pageable()
.Sortable()
.Filterable()
)
but my problem is i need to add below line of code to my grid(in first code mentioned above).
.ToolBar(toolBar =>
toolBar.Custom()
.Text("Export To Excel")
.HtmlAttributes(new { id = "export" })
.Url(Url.Action("Export", "Home", new { page = 1, pageSize = "~", filter = "~", sort = "~" }))
)
but im stucked with this single line
.Url(Url.Action("Export", "Home", new { page = 1, pageSize = "~", filter = "~", sort = "~" }))
can somebody please tell me that how to use this code in my html grid..
Write Toolbar manual
<div class="k-toolbar k-grid-toolbar k-grid-top">
<a class="k-button k-button-icontext " id="exportCsv" href="/Home/ExportToCsv?take=50&skip=0&page=1&pageSize=10&filter=~&sort=" id="exportToCSV"><span></span>Export CSV</a>
<a class="k-button k-button-icontext " id="exportXls" href="/Home/ExportToXls?take=50&skip=0&pageSize=10&filter=~&sort=" id="exportToExcel"><span></span>Export Excel</a>
</div>
then add databound to kendoGrid
....
editable: false, // enable editing
sortable: true,
filterable: true,
scrollable: false,
dataBound: onDataBound,
columns: [.....
then write 'onDataBound' function
<script>
function onDataBound(e) {
var grid = $('#grid').data('kendoGrid');
var take = grid.dataSource.take();
var skip = grid.dataSource.skip();
var page = grid.dataSource.page();
var sort = grid.dataSource.sort();
var pageSize = grid.dataSource.pageSize();
var filter = JSON.stringify(grid.dataSource.filter());
// Get the export link as jQuery object
var $exportLink = $('#exportXls');
// Get its 'href' attribute - the URL where it would navigate to
var href = $exportLink.attr('href');
// Update the 'take' parameter with the grid's current page
href = href.replace(/take=([^&]*)/, 'take=' + take || '~');
// Update the 'skip' parameter with the grid's current page
href = href.replace(/skip=([^&]*)/, 'skip=' + skip || '~');
// Update the 'page' parameter with the grid's current page
href = href.replace(/page=([^&]*)/, 'page=' + page || '~');
// Update the 'sort' parameter with the grid's current sort descriptor
href = href.replace(/sort=([^&]*)/, 'sort=' + sort || '~');
// Update the 'pageSize' parameter with the grid's current pageSize
href = href.replace(/pageSize=([^&]*)/, 'pageSize=' + pageSize);
//update filter descriptor with the filters applied
href = href.replace(/filter=([^&]*)/, 'filter=' + (filter || '~'));
// Update the 'href' attribute
$exportLink.attr('href', href);
$('#exportCsv').attr('href', href.replace('ExportToXls', 'ExportToCsv'));
}
</script>
And this is the Action, and parameters
public FileResult ExportToXls(int take, int skip, IEnumerable<Sort> sort, string filter)
{
try
{
Filter objfilter = JsonConvert.DeserializeObject<Filter>(filter);
var lstContactFormData = XmlData.GetIletisimBilgileri().OrderByDescending(i => i.tarih);
//Get the data representing the current grid state - page, sort and filter
//IEnumerable products = _db.Products.ToDataSourceResult(request).Data;
IEnumerable contactsDatas = lstContactFormData.AsQueryable().ToDataSourceResult(take, skip, sort, objfilter).Data;
...
...
I am trying to fetch data from store.and i want to use it on my table layout in an extjs panel but always get an empty string though the data is printed in the console. Any pointers would be much appreciated.
<code>
Ext.onReady(function(){
Ext.define('Account', {
extend: 'Ext.data.Model',
fields: [
'id',
'name',
'nooflicenses'
]
});
var store = Ext.create('Ext.data.Store', {
model: 'Account',
autoSync: true,
proxy: {
type: 'ajax',
api: {
read: "accounts"
},
reader: {
type: 'json',
root: 'Account',
successProperty: 'success',
messageProperty: 'message',
totalProperty: 'results',
idProperty: 'id'
},
listeners: {
exception: function(proxy, type, action, o, result, records) {
if (type = 'remote') {
Ext.Msg.alert("Could not ");
} else if (type = 'response') {
Ext.Msg.alert("Could not " + action, "Server's response could not be decoded");
} else {
Ext.Msg.alert("Store sync failed", "Unknown error");}
}
}//end of listeners
}//end of proxy
});
store.load();
store.on('load', function(store, records) {
for (var i = 0; i < records.length; i++) {
console.log(store.data.items[0].data['name']); //data printed successfully here
console.log(store.getProxy().getReader().rawData);
console.log(store);
};
});
function syncStore(rowEditing, changes, r, rowIndex) {
store.save();
}
var rowEditing = Ext.create('Ext.grid.plugin.RowEditing', {
clicksToMoveEditor: 1,
autoCancel: false,
saveText: 'Save',
listeners: {
afteredit: syncStore
}
});
var grid = Ext.create('Ext.panel.Panel', {
title: 'Table Layout',
width: 500,
height:'30%',
store: store,
layout: {
type: 'table',
// The total column count must be specified here
columns: 2,
tableAttrs: {
style: {
width: '100%',
height:'100%'
}
},
tdAttrs: {
style: {
height:'10%'
}
}
},
defaults: {
// applied to each contained panel
bodyStyle:'border:0px;',
xtype:'displayfield',
labelWidth: 120
},
items: [{
fieldLabel: 'My Field1',
name :'nooflicenses',
value: store //How to get the data here
//bodyStyle:'background-color:red;'
},{
fieldLabel: 'My Field',
name:'name',
value:'name'
}],
renderTo: document.getElementById("grid1")
});
});
</code>
Ext.grid.Panel control is totally configurable so it allows to hide different parts of the grid. In our case the way to hide a headers is adding property: hideHeaders:
Ext.create("Ext.grid.Panel", {
hideHeaders: true,
columns: [ ... ],
... other options ...
});
If you still would like to adopt another solution, the more complex solution I have think about is the use of XTemplate for building table dynamically. (http://docs.sencha.com/ext-js/4-1/#!/api/Ext.XTemplate). In this approach you write the template describing how the table will be built.
Otherwise, I still recommend you to deal with the former solution rather than the latter one. The latter approach opposes the basic idea of Sencha ExtJS: use ExtJS library's widgets, customize them in the most flexible way and then automate them by creating store and model.
The most "native" way to show data is by use Ext.grid.Panel.
Example:
Ext.application({
name: 'LearnExample',
launch: function() {
//Create Store
Ext.create ('Ext.data.Store', {
storeId: 'example1',
fields: ['name','email'],
autoLoad: true,
data: [
{name: 'Ed', email: 'ed#sencha.com'},
{name: 'Tommy', email: 'tommy#sencha.com'}
]
});
Ext.create ('Ext.grid.Panel', {
title: 'example1',
store: Ext.data.StoreManager.lookup('example1'),
columns: [
{header: 'Name', dataIndex: 'name', flex: 1},
{header: 'Email', dataIndex: 'email', flex: 1}
],
renderTo: Ext.getBody()
});
}
});
The grid can be configured in the way it mostly customized for user's needs.
If you have a specific reason why to use Ext.panel.Panel with a table layout, you can use XTemplate, but it more complicate to bind the data.