I have a service created with spring boot, for which I am trying to display its data using the bootstrap-table library.
My service allows pagination with the query parameters ?page=x&size=y, where page starts at 0.
The response for the query returns something that looks like this:
{
"_embedded": {
"catalogueOrders": [ .... ]
},
"page": {
"size": 20,
"totalElements": 11,
"totalPages": 1,
"number": 0
}
}
Where _embedded.catalogueOrders contains all the data, and page contains the totals.
I tried configuring my table as following:
$('#orderTable').bootstrapTable({
url: "http://localhost:8088/catalogueOrders?orderStatus=" + orderState,
columns: [
{
field: 'orderId',
title: 'Order ID'
},
{
field: 'priority',
title: 'Priority'
}
],
pagination: true,
sidePagination: 'server',
totalField: 'page.totalElements',
pageSize: 5,
pageList: [5, 10, 25],
responseHandler: function(res) {
console.log(res)
return res["_embedded"]["catalogueOrders"]
}
})
This is able to retrieve and display the data, however it returns all the results, clearly due to it not knowing how to apply the pagination. Total elements doesn't seem to be retrieved either, as the table displays Showing 1 to 5 of undefined rows. Also, if I replace the responseHandler with dataField: '_embedded.catalogueOrders', it's no longer displaying the data.
How do I configure the query parameters needed for pagination?
And am I doing anything wrong when I try and configure dataField and totalField?
Figured it out:
Not sure what was wrong with the dataField and totalField, but it seems to not work with nested fields. To resolve this, I formatted the response into a new object inside responseHandler:
dataField: 'data',
totalField: 'total',
responseHandler: function(res) {
return {
data: res["_embedded"]["catalogueOrders"],
total: res["page"]["totalElements"]
}
}
As for the query parameters, by default, bootstrap-table provides the parameters limit and offset. To customize that and convert to size and page like in my case, the queryParams function can be provided:
queryParams: function(p) {
return {
page: Math.floor(p.offset / p.limit),
size: p.limit
}
}
one, yes, it doesn’t work with nested fields. if you want to use nested fields, try on sass code (get the compiler, just search up on web, there’s plenty of posts on the web).
two, i’m not exactly sure what you’re talking about, but you can set up a css variable
:root{
/*assign variables*/
—-color-1: red;
—-color-2: blue;
}
/*apply variables
p {
color: var(-—color-1):
}
you can find loads of info on this on the web.
Related
I'm working with this bootstrap library and actually everything works fine. The question is, Can bootstrap-table generate header automatically in depend of JSON file? I've tried to find any information about that, but unlucky. Now my header is generated from script like from this example:
function initTable() {
$table.bootstrapTable({
height: getHeight(),
columns: [{
field: 'field1',
title: 'title1',
sortable: true
}, {
field: 'field2',
title: 'title2',
sortable: true
}, {
field: 'field3',
title: 'title3',
sortable: true
}, {
field: 'Actions',
title: 'Item Operate',
align: 'center',
events: operateEvents,
formatter: operateFormatter
}
],
formatNoMatches: function () {
return "This table is empty...";
}
});
Does anyone how to generate header automatically?
Populating from a flat json file is definetly possible but harder than from a seperate (slimmer and preped) data request, because title and other attributes 'might' have to be guessed at.
Ill show basic approach, then tell you how to make it work if stuck with a flat file that you CAN or CANT affect the format of (important point, see notes at end).
Make a seperate ajax requests that populates var colArray = [], or passes direct inside done callback.
For example, in callback (.done(),.success(), ect) also calls to the function that contains the js init code for the table.
You might make it look something like this:
function initTable(cols) {
cols.push({
field: 'Actions',
title: 'Item Operate',
align: 'center',
events: operateEvents,
formatter: operateFormatter
});
$("#table").bootstrapTable({
height: getHeight(),
columns: cols,
formatNoMatches: function () {
return "This table is empty...";
}
});
}
$(document).ready(function(){
$.ajax({
method: "POST",
url: "data/getColumns",
// data: { context: "getColumns" }
datatype: "json"
})
.done(function( data ) {
console.log( "getCols data: ", data );
// Prep column data, depending on what detail you sent back
$.each(data,function(ind,val){
data.sortable = true;
});
initTable(data);
});
});
Now, if you are in fact stuck with a flat file, point the ajax towards that then realise the question is whether you can edit the contents.
If yes, then add a columns array into it with whatever base data (title, fieldname, ect) that you need to help build your columns array. Then use responseHandler if needed to strip that columns array if it causes issues when loading into table.
http://bootstrap-table.wenzhixin.net.cn/documentation/#table-options
http://issues.wenzhixin.net.cn/bootstrap-table/ (click 'see source').
If no, you cant edit contents, and only have the fieldname, then look at using that in the .done() handler with whatever string operation (str_replace(), ect) that you need to make it look the way you want.
Ok I'm pretty sure I know exactly what I need to do here but I'm not sure how to do it. Basically I have a grid that I want to make a key column bind to an array of key/values, which I've done before with kendo (not using Angular) and I know that when I'm creating my key/value array asynchronously then that needs to complete before I can get them show-up with kendo, which I have done using promises before.
So here I have the same issue only angular is also involved. I need to fetch and format an array of data into the format in which a kendo grid column can digest it, so no problem here is my controller code:
var realm = kendo.data.Model.define({
id: 'realmID',
fields: {
realmID: { editable: false, nullable: true }
realmType: { type: 'string', validation: { required: true } }
}
})
var ds1 = kendoHelpers.dataSourceFactory('realms', realm, 'realmID')
var realmType = kendo.data.Model.define({
id: 'realmTypeID',
fields: {
realmTypeID: { editable: false, nullable: true },
name: { type: 'string', validation: { required: true } }
}
})
var ds2 = kendoHelpers.dataSourceFactory('realms/types', realmType, 'realmTypeID')
$scope.mainGridOptions = {
dataSource: ds1,
editable: true,
navigatable: true,
autoBind:false,
toolbar: [
{ name: "create" },
{ name: 'save' },
{ name: 'cancel' }
],
columns: [
{ field: 'realmID', title: 'ID' }
{ field: 'realmTypeID', title: 'Realm Type', editor: realmTypesDDL, values: $scope.realmTypeValues },
{ command: "destroy" }
]
}
$scope.secondGridOptions = {
dataSource: ds2,
editable: true,
navigatable: true,
toolbar: [
{ name: "create" },
{ name: 'save' },
{ name: 'cancel' }
],
columns: [
{ field: 'realmTypeID', title: 'ID' },
{ field: 'name', title: 'Name' }
{ command: "destroy" }
]
}
ds2.fetch(function () {
$scope.realmTypeValues = [{ text: 'Test', value: "24bc2e62-f761-4e70-804c-bc36fdeced3d" }];
//this.data().map(function (v, i) {
// $scope.realmTypeValues.push({ text: v.name, value: v.realmTypeID})
//});
//$scope.mainGridOptions.ds1.read()
});
function realmTypesDDL(container, options) {
$('<input />')
.appendTo(container)
.kendoDropDownList({
dataSource: ds2,
dataTextField: 'name',
dataValueField: 'realmTypeID'
});
}
I made this dataSourceFatory helper method above to return me a basic CRUD kendo dataSource that uses transport and also injects an authorization header which is working fine so don't get hung up on that, ultimately I'm going to be using this data in another grid as well as for reference values for the main grid, but I've hard coded some values that I can use to test with in the ds2.fetch callback.
My HTML is pretty plain:
<div>
<h2>Realms</h2>
<kendo-grid options="mainGridOptions"></kendo-grid>
<h2>Realm Types</h2>
<kendo-grid options="secondGridOptions"></kendo-grid>
</div>
This all works fine and well except I am only seeing the GUID of the realmTypeID in the grid, I click it and the editor is populated correctly so that's good but I want the text value to be displayed instead of the GUID. I'm sure the issue is that the array of values is empty whenever angular is binding to the grid options. My questions are:
How do I either delay this bind operation or manually rebind it after the fetch call?
Is there a better way to handle a situation like this? I try not to expend finite resources for no reason (IE making server calls when unnecessary)
Note: When I move the creation of the text/value array to happen before the grid options, I get the desired behavior I am after
EDIT A work around is to not use the directive to create the grid and instead defer the grid creation until the callback of whatever data your column is dependent on, I was hoping for a more elegant solution but this is better than nothing. So your HTML becomes something like
<h2>Realms</h2>
<div id="realms"></div>
<h2>Realm Types</h2>
<kendo-grid options="secondGridOptions"></kendo-grid>
Then you can create the grid in the fetch callback for example:
ds2.fetch(function () {this.data().map(function (v, i) {
$scope.realmTypeValues.push({ text: v.name, value: v.realmTypeID})
});
$('#realms').kendoGrid($scope.mainGridOptions);
$scope.mainGridOptions.dataSource.fetch()
});
But this doesn't feel very angularish so I'm really hoping for a better solution!
Ok...well I think I hacked this enough and without another suggestion I'm going to go forward with this approach. I'm just going to move the binding logic to the requestEnd event of the second grid so that the values array can be populated right before the binding even. I'm also reworking the values array in this method. It is a bit weird though, I think there is some kendo black magic going on with this array because I can't just set it to a new empty array without it breaking completely...which is why I'm poping everything out prior to repopulating the array. That way when something is deleted or edited in the second grid, the DDL in the first grid is updated in the callback.
function requestEnd(e) {
for (var i = $scope.realmTypeValues.length; i >= 0; i--) $scope.realmTypeValues.pop();
var data;
if (e.type == "read")
data = e.response;
else
data = e.sender.data();
data.map(function (v, i) { $scope.realmTypeValues.push({ text: v.name, value: v.realmTypeID }); });
if ($('#realms').data('kendoGrid') == undefined) {
$('#realms').kendoGrid($scope.mainGridOptions);
}
else
$('#realms').data('kendoGrid').columns[4].values = $scope.realmTypeValues;
}
ds2.bind('requestEnd', requestEnd);
So I'm going to accept my own answer unless anyone has a better approach!
I'm trying to connect a dojo dgrid to a solr data service and need some help.
When I use jsonp I can get connected to the solr data and output the data result to the screen with something like this:
dojo.require("dojo.io.script");
function searchGoogle(){
// Look up the node we'll stick the text under.
var targetNode = dojo.byId("output");
// The parameters to pass to xhrGet, the url, how to handle it, and the callbacks.
var jsonpArgs = {
url: "myExternalSolrURL",
callbackParamName: "json.wrf",
content: {
wt: "json",
rows: "12",
start: "1",
q: "*"
},
load: function(data){
// Set the data from the search into the viewbox in nicely formatted JSON
targetNode.innerHTML = "<pre>" + dojo.toJson(data, true) + "</pre>";
},
error: function(error){
targetNode.innerHTML = "An unexpected error occurred: " + error;
}
};
dojo.io.script.get(jsonpArgs);
}
dojo.ready(searchGoogle);
But, when I try to use jsonrest to connect to the solr data and get it to show up in a dgrid nothing appears to happen. This is the code I have for that:
<script>
var myStore, dataStore, grid;
require([
"dojo/store/JsonRest",
"dojo/store/Memory",
"dojo/store/Cache",
"dgrid/Grid",
"dojo/data/ObjectStore",
"dojo/query",
"dijit/form/Button",
"dojo/domReady!"
], function (JsonRest, Memory, Cache, Grid, ObjectStore, query, Button, domReady) {
myStore = Cache(JsonRest({
target: "myExternalSolrURL",
idProperty: "id"
}),
Memory({ idProperty: "id" }));
grid = new Grid({
store: dataStore = ObjectStore({ objectStore: myStore }),
structure: [
{ name: "Thing id", field: "id", width: "50px" },
{ name: "Name", field: "name", width: "200px" },
{ name: "detail", field: "detail", width: "200px" }
]
}, "grid"); // make sure you have a target HTML element with this id
grid.startup();
});
</script>
<div style="height: 300px; width: 600px; margin: 10px;">
<div id="grid">
</div>
</div>
Does anyone see what I am missing?
You changed your code to use dgrid, but it looks like you are still attempting to use a dojo/data store with dgrid. dgrid only supports the dojo/store API, so stop wrapping your store in ObjectStore.
dgrid/List and dgrid/Grid do not contain store logic. You will want to either use dgrid/OnDemandGrid or mix in dgrid/extensions/Pagination.
Make sure the service you are using with dojo/store/JsonRest actually behaves as the store implementation expects (or use or write a diffrent dojo/store implementation)
Apparently part of the problem is that a Solr index is not a flat data structure like a grid or dgrid can deal with. When you have nested data returned like a Solr or ElasticSearch index will return it must be "flattened" to go into a grid. However, this sort of hierarchy of data will work with a tree vs a grid. So the next challenge is to connect to the index and flatten it.
I'm trying to learn how to use the EXTJS grids for some simple CRUD operations over a table in a admin app.
I have a simple grid that allows someone to edit users, the store is defined as:
var userDataStore = new Ext.data.Store({
id: 'userDataStore',
autoSave: false,
batch: true,
proxy: new Ext.data.HttpProxy({
api: {
read: '/Admin/Users/All',
create: '/Admin/Users/Save',
update: '/Admin/Users/Save'
}
}),
reader: new Ext.data.JsonReader(
{
root: 'Data',
idProperty: 'ID',
totalProperty: 'total',
successProperty: 'success',
messageProperty: 'message'
}, [
{ name: 'ID', type: 'string', allowBlanks: false },
{ name: 'NT_ID', type: 'string', allowBlank: false },
{ name: 'EMail', type: 'string', allowBlank: false },
{ name: 'Name', type: 'string', allowBlank: false },
{ name: 'Enabled', type: 'bool', allowBlank: false },
{ name: 'CurrentRoleCode', type: 'string', allowBlank: false}]
),
writer: new Ext.data.JsonWriter(
{
encode: false,
writeAllFields: true,
listful: true
})
});
This is bound to a grid, and I am able to load and save users without issue. The save button looks like this:
var saveButton = new Ext.Button({
text: 'Save',
disabled: true,
handler: function() {
userDataStore.save();
pageState.ClearDirty();
saveButton.disable();
}
});
However, when creating a new user, the JSON POST for the user is posted to the same REST service end point as "Update", with the only difference being that no ID value is posted (as one is only set in the store when loading from the server).
This works, and I am able to create users.
The save REST service emits back the created row with the new database ID, and I was under the assumption that EXTJS would automatically bind the new generated database ID to the row. This allows the user to further edit that row, and cause an update instead of a insert.
Instead, the row continues to have a blank user ID, so an additional save creates another new user.
So either:
EXTJS is supposed to resolve generated row ID's automatically and I am just doing something wrong.
I am supposed to manually reload the grid after each save with an additional REST call.
I've been looking at EXTJS documentation and forums, but I am unclear on the proper approach.
Can someone clarify?
EDIT: I tried returning Success = True in JSON to match the SuccessProperty, however this still didn't seem to work.
EDIT #2: So far the only thing I've found that works is doing "userDataStore.reload()" after saving, however because I was returning the contents of the store back after saving, I was hoping that EXTJS would understand that and update the row values.
I've got an idea that may help you. Let't suppose that user added a new
record in grid, in that moment add a new property newRecOrderNo to the record to
identify the record after response. When user will post data to server after
inserting you must get a new ID and associate it to newRecOrderNo
(like Map<Integer,Integer>). Then return json object like that :
{
success : true,
newIdes : {
1 : 23,
2 : 34
}
}
Then when you get response do set proper IDs to records:
userDataStore.each(function(rec){
if(rec.data.newRecOrderNo){
rec.data.ID = response.newIdes[rec.data.newRecOrderNo];
delete rec.data.newRedOrderNo;
}
})
})
Yes, it sets id (and also other fields, if server returns modified values of them), if create ajax backend returns record with set id, at least in extjs 4.1. You should return inserted record, with id set, under 'root' key as json dictionary, in this example root is 'Data', i.e.:
{
"Data": {
"ID": 8932,
"NT_ID": 28738273,
...
"CurrentRoleCode": "aaa",
},
"success": true
}
You need reload store with new params in savebtn handler
like
store.reload();
of course you can add more params to load action
In flot, how can I create a pie chart where each wedge is a link to a different web-page?
I gave it a shot, but I wasn't able to do it. I started with this example, then added:
grid: { clickable: true },
right above the "pie: {" line. Then I added a plotclick function at the end:
$("#placeholder").bind("plotclick", function (event, pos, item) {
alert('click!');
for(var i in item){
alert('my '+i+' = '+ item[i]);
}
});
You'll see the "click!" message, but "item" has no properties.
I was thinking you'd just add URLs to the data ojects, then forward the browser to the appropriate URL from within the plotclick function. If you figure it out, I'd be interested to know!
Update: Here's something that might work -- it just turns the labels into links. Put the URLs in your data like this:
$.plot($("#placeholder"), [
{ label: "Serie1", data: 10, url: "http://stackoverflow.com"},
{ label: "Serie2", data: 30, url: "http://serverfault.com"},
{ label: "Serie3", data: 90, url: "http://superuser.com"},
{ label: "Serie4", data: 70, url: "http://www.google.com"},
{ label: "Serie5", data: 80, url: "http://www.oprah.com"},
{ label: "Serie6", data: 110, url: "http://www.realultimatepower.net/"}
],
Then set the labelFormatter to something like:
return ''+serie.label+'<br/>'+Math.round(serie.percent)+'%';
Clicking in the pie wedges themselves still does nothing special, though.
I know this is an old thread but I have discovered another way of doing this.
Make sure grid is set to clickable
var data = [{
"label" : "series1",
"data" : 24,
"url" : "http://stackoverflow.com"
},
{
// etc etc
}];
$.plot($('.chart'), data, function() {
// Your options
grid: {
clickable:true
}
});
Bind a click function to the element and use javascript to redirect to the url.
$('.chart').bind("plotclick", function(event,pos,obj) {
window.location.replace(data[obj.seriesIndex].url);
});
Adding to the answer by Derek Kurth...
It looks like flot is ignoring any additional objects that we include in the JSON. For example when I used
data: [10, 0, "http://stackoverflow.com"]
// 0 is used as an intercept value for y-axis
it worked without any trouble and I was able to access the data from the event handler like
$("#placeholder").bind("plotclick", function (event, pos, item) {
alert(item.series.data);
});
I am new to this flot library and not great at JavaScript. So probably this is not the right way to do things but it works. I have always felt that embedding additional information in UI elements in HTML is a pain :(