I want to display data in a sencha comboboxfield, however the dataset has 15,000+ records and it is not feasible to load it all at one time. What I would like to do is have the sencha extreact comboboxfield:
Load remotely (restful api)
return a subset (25 records) that can be scrolled through (infinite scrolling - get next 25 and so on).
filter data based on data typed by the user. This would be a refresh of the data not filter what has already been fetched.
I've read through the documentation and sounds like I may need to use ExtJs store and proxy but for some reason it's not getting through my thick skull :). Any examples I have found appear to have the proxy setup that requires you access the api directly. I cannot do this because I'm working within a framework where that is not possible. All calls need to go through an async function due to authentication, logging and other purposed. If anyone has some pointers or examples to share that would be greatly appreciated.
I've had to make some tweaks to our system but I have this working and thought I would share. I have to give credit to this thread for pointing me in the right direction. Forgive me in advance for formatting issues.
First off, I couldn't figure out how to get the proxy to call a function so just went with the Ext.data.proxy.Ajax approach. A bit of a work around for me but it works. Here is my store and proxy setup (this is placed into component state):
postalCodes = (props) => {
let postalCodeStore = new Ext.data.Store ({
proxy: {
type: 'ajax',
url: postalCodesApiRoutes.DROPDOWNDATA, //stores my api route information
reader: {
type: 'json',
rootProperty: 'postalCode',
totalProperty: 'totalRecordCount'
},
pageParam: 'index',
extraParams: {
pageSize: props.pageSize
},
headers: { ...authHeader(), // returns my authentication header info
<OTHER LOGGING INFO WENT HERE>
},
noCache: false
},
autoLoad: false,
pageSize: props.pageSize,
clearOnPageLoad: false
})
return postalCodeStore;
}
The following is my ComboBoxField config (note: I had to use this.handlePickerCreate.bind(this) because the sencha controls don't appear to honor the arrow function binding):
<ComboBoxField
displayField="value"
valueField="postalCodeId"
queryMode="remote"
store={this.state.postalCodes}
remoteFilter={true}
clearable
allQuery=""
triggerAction="all" // I want when the dropdown clicked on it ignores whats in the combobox text and queries the entire data set. Otherwise if a user types a value a server-side filter will be executed.
queryParam="filter"
onPickerCreate={this.handlePickerCreate.bind(this)}
/>
The following is the handlePickerCreate and onScroll functions:
handlePickerCreate = (obj, picker) => {
picker.getScrollable().on('scroll', this.onScroll);
}
onScroll = (scroller, x, y, deltaX, deltaY, opts) => {
if (y >= scroller.getMaxPosition().y) {
let sStore = this.state.areas;
if (sStore.getTotalCount() != sStore.getCount()){
sStore.nextPage({
callback: function () {
scroller.doScrollTo(0, y);
console.log('store count', sStore.getCount())
}
});
this.setState({areas: sStore})
}
}
}
Anyway, there are still some quirks that I'm trying to figure out like when a value is selected from the list then you click on the trigger/dropdown arrow the picker displays and immediately disappears and the combobox input field clears out. I see a call being made to the server and data being returned but can't figure out what is happening. Well hope this helps someone.
Related
I hope its not to harsh to ask not to mince matters.
Here we go:
I have a problem developing a custom Plugin for Shopware 5.
I already have a working plugin which lists orders for certain criteria.
Now I want a Button (which i already have) in the toolbar of this grid-window.
The Button should open the Batch Process Window which is already available in the native "Order" Window of shopware.
Q: How Can I open this app with the selected Ids of my grid?
Heres what I have:
[...]
createToolbarButton: function () {
var me = this;
return Ext.create('Ext.button.Button', {
text: 'Batch Processing Orders',
name: 'customBatchProcessButton',
cls: 'secondary',
handler: function () {
me.onClickCustomBatchProcessButton(me);
}
});
},
onClickCustomBatchProcessButton: function(me){
var thisGrid = me.getTransferGrid();
var records = thisGrid.getSelectionModel().getSelection();
console.log("Grid");
console.log(thisGrid);
console.log("records");
console.log(records);
Shopware.app.Application.addSubApplication({
name: 'Shopware.apps.Order',
action: 'batch',
params: {
mode: 'multi',
records: records
}
});
}
[...]
It always opens the normal view of the order window. (no error in console)
Anybody has a suggestions?
That would be great!
Thanks for your time :)
Greetings
EDIT:
Hey, thank you for your reply so far.
I managed to open the Batch-process-window like this:
me.getView('Shopware.apps.Order.view.batch.Window').create({
orderStatusStore: Ext.create('Shopware.apps.Base.store.OrderStatus').load(),
records: orderRecords,
mode: 'multi'
}).show({});
But now the Problem ist, the Event for the Batch-Process isn't applied on the button on the form...
I am still on try and error.
Many Shopware ExtJS SubApplications can be executed from another app with certain parameters exactly the way you're trying to. Unfortunately I don't see any code in the Order plugin that might lead to the desired result. You can see what actions/params a Shopware SubApplication supports by reading the init function of the main controller -> Shopware.apps.Order.controller.Main
Shopware.apps.Customer.controller.Main from the Customer plugin for example accepts an action like you are using it – it is checking for this:
if (me.subApplication.action && me.subApplication.action.toLowerCase() === 'detail') {
if (me.subApplication.params && me.subApplication.params.customerId) {
//open the customer detail page with the passed customer id
...
In the Order plugin there is similar code, but it just takes an order ID and opens the detail page for the corresponding order. It apparently doesn't feature the batch.Window
You might be able to reuse this class somehow, but that might be a ton of code you need to adapt from the actual Order plugin. If you really need this feature, you can carefully read how the Order plugin is initializing the window and its dependencies and have a try.
I'd rather go for developing a lightweight module in this scenario (It's a frame within a backend window that just uses controllers and template views with PHP/Smarty/HTML)
I have created a custom section in umbraco to manage some data in an SQL database.
I can edit items OK but when adding I need to refresh the page to see my new row in the custom tree on the left.
How can I cause a refresh of my custom tree using AngularJS? My tree is called "clients".
I have tried debugging the code and looking at the source to find the event but I can't seem to work out how to do it.
Is there a method I can call on the umbTreeDirective somehow? Or an event to subscribe to?
I am fairly new to AngularJS and am struggling a little.
You're looking for the navigationService.
This line is example of a syncTree call:
navigationService.syncTree({ tree: 'clients', path: content.path, forceReload: false, activate: true });
Here's a contrived, spaghetti promised but full example:
angular.module("umbraco")
.directive('nowplaying', ['navigationService', 'contentResource', 'contentEditingHelper', function (navigationService, contentResource, contentEditingHelper) {
//spaghetti example to create new document
contentResource.getScaffold(parentId, alias)
.then(function (scaffold) {
var myDoc = scaffold;
myDoc.name = name;
//we have minimum to publish
contentResource.publish(myDoc, true, [''])
.then(function (content) {
$scope.newlyCreatedNode = content;
//Sync ('refresh') the tree!
navigationService.syncTree({ tree: 'clients', path: content.path, forceReload: false, activate: true });
});
});
}]);
All of the Belle documentation lives here. -I'm not sure it's actively maintained, i can say for certain that one or two signatures have changed since it was first posted. That aside, it's the best resource i know of to interact with all the umbraco exposed modules and services.
this question has already been answered multiple times. but here I want to site that if the code provided in the documentation can't be achieved without additional codes, why it has been given there in first place. Its simply misleading. The code given in the documentation achieves paging, but while sorting, the grid data simply disappears.
Correct me if I am wrong.
jQuery("#gridid").jqGrid({
...
datatype: 'json', // can be xml
loadComplete : function () {
jQuery("#gridid").jqGrid('setGridParam',{datatype:'local'});
},
onPaging : function(which_button) {
jQuery("#gridid").jqGrid('setGridParam',{datatype:'json'});
},
...
});
You don't posted the exact reference to the documentation where you get the code. I found it here.
jqGrid is open source product which you get for free. It's practical, but you should understand, that in the case the product and its documentation could not be perfect. The part of code which you referenced could work probably in some very old version of jqGrid, but it's wrong code in the current version of jqGrid. The sense of implementing "Client side sorting, but server side paging" is very suspected at all. My old answer about the subject you would find here. I would rewrite some part of the answer now, but in general the code tested with old versions could be not full compatible with the new version of jqGrid.
I can say there is no place where intentional misleading has happened. They are giving the pluging for free though it is a very huge plugin. And the work done by people like Oleg is making it more perfect. For you question, the code related to "client side sorting and server side paging" here is the code that can solve your problems. And this was taken with the help of some old answer given by Oleg.
This is my version of code,
loadComplete: function(data) {
var $this = $(this);
if ($this.jqGrid('getGridParam', 'datatype') === 'json') {
// because one use repeatitems: false option and uses no
// jsonmap in the colModel the setting of data parameter
// is very easy. We can set data parameter to data.rows:
$this.jqGrid('setGridParam', {
datatype: 'local',
data: data.userdata,
pageServer: data.page,
recordsServer: data.records,
lastpageServer: data.total
});
// because we changed the value of the data parameter
// we need update internal _index parameter:
this.refreshIndex();
if ($this.jqGrid('getGridParam', 'sortname') !== '') {
// we need reload grid only if we use sortname parameter,
// but the server return unsorted data
$this.triggerHandler('reloadGrid');
}
} else {
$this.jqGrid('setGridParam', {
page: $this.jqGrid('getGridParam', 'pageServer'),
records: $this.jqGrid('getGridParam', 'recordsServer'),
lastpage: $this.jqGrid('getGridParam', 'lastpageServer')
});
this.updatepager(false, true);}
}
onPaging:function(){
/*this code is to fix the issue when we click on next page with some data in filter tool bar
* along with this in grid definition( in filterToolbar ) we have to return true in "beforeClear "event
* */
var data = $(this).jqGrid("getGridParam", "postData");
data._search = false;
data.filters=null;
data.page=$(this).jqGrid("getGridParam","page");
/* comment this line if you disable filter toolbar*/
$(this)[0].clearToolbar();
//Here making _search alone false will not solve problem, we have to make search also false. like in below.
$(this).jqGrid('setGridParam', { search: false, postData:data });
var data = $(this).jqGrid("getGridParam", "postData");
/*this is to fix the issue when we go to last page(say there are only 3 records and page size is 5) and click
* on sorting the grid fetches previously loaded data (may be from its buffer) and displays 5 records
* where in i am expecting only 3 records to be sorted out.along with this there should be a modification in source code.
*/
$(this).jqGrid("clearGridData");
/* this is to make the grid to fetch data from server on page click*/
$(this).setGridParam({datatype: 'json'}).triggerHandler("reloadGrid");
}
For the modification that you have to do in source code is , see this answer..
I've been googling this and can't seem to find an answer. I will also ask this in the JavaScript InfoVis Toolkit Google Group.
I was wondering if it's possible to dynamically hide/show tooltips using InfoVis spacetree. Currently they are turned on and I have set up the tips like this:
Tips: {
enable: true,
type: 'HTML',
offsetX: 10,
offsetY: 10,
onShow: function (tip, node)
{
tip.innerHTML = getToolTip(node);
}
},
but I can't seem to find any references for how I might turn them off later. For example, I want the user to be able to check a box to hide/show Tooltips and then display them accordingly. I tried st.tips.hide() (st is the name of my spacetree) but it doesn't do anything. If I do alert(st.tips) I get an object but I don't know what functions are available on the object.
Any help would be much appreciated! Thanks!
I'm using ForceDirected and had a similar problem. I wanted to keep the tooltip displayed for a certain period of time after the user leaves the node with the cursor...
Calling
graph.tips.hide(false)
works for me (did you ever try passing an argument to hide?).
I can't tell you whether to pass true or false, they both work for me...
Overall you could try something like:
Tips: {
enable: true,
type: 'HTMl',
onShow: function(tip, node, isLeaf, domElement) {
//Check if checkbox is checked
var checked = $('input[type=checkbox]').is(':checked');
if (checked == true){
tip.innerHTML = getToolTip(node);
} else {
graph.tips.hide(true);
};
}
In any case this is just an idea and I don't have the time to test it (pseudocode?..)
Hope this helped!
Cheers
I've been digging around for this one quite a bit. I'm using dojox.grid.datagrid and I have an ajax call that brings back 200-300 rows.
The grid renders and scrolls just fine in Chrome but scrolling is excruciatingly slow in IE 7 and 8. I'd like to use virtual scrolling to try and remedy the issue but can't find any sample code.
Here's what my code looks like at present.
function setupAvailableScenes(location) {
var avaiableScenesGridPane = dijit.byId("AvaiableScenesGridPane");
var availableScenesGrid = dijit.byId("AvailableScenesGrid");
if (_isFirstLoad) {
availableScenesGrid = new dojox.grid.DataGrid({
id: 'AvailableScenesGrid',
store: availableScenesStore,
query: { Id: "*" },
sortInfo: "1",
rowsPerPage: 20,
autoHeight:20,
style: "width:315px",
structure: [
{ name: "Available Scenes", field: "Name", width: "85%" },
{ name: " ",
field: "_item",
rowsPerPage: "25",
type: dojox.grid.cells._Widget,
editable: false,
width: "15%",
formatter: function (scene) {
return new dijit.form.Button(
{
label: "+",
onClick: function () {
AddSceneToSelectedScenes(scene);
}
})
}
}
]
});
avaiableScenesGridPane.set('content', availableScenesGrid);
}
var availableScenesStore = new dojo.data.ItemFileWriteStore({
url: _applicationPath + "/Location/" + location.Id + "/Scene.json",
preventUrlCache: true
});
availableScenesGrid.setStore(availableScenesStore);
}
Often one of the biggest things you can do to improve DataGrid performance is to throw away the ItemFileReadStore/WriteStore and use an optimized data store (personally I like QueryReadStore). It would mean needing a server-side servlet of some kind (PHP/JSP/etc) to handle the virtual scrolling/pagination, but I've seen major perf boosts over just using a store backed by a JSON file.
Some other things to consider, which may or may not help:
give your anonymous formatter function a name and try scrolling the table with the Chrome or Firebug profiles turned on to see if it's hogging a lot of cycles (or, like Vijay Agrawal said, you could try replacing the dijit.form.Button with a vanilla html <button> tag)
you shouldn't actually need to specify the dojox.grid.cells._Widget type for that cell; having a custom formatter returning a valid Dijit should be sufficient to make the Grid do the right thing.
Since you specified rowsPerPage=25, it is already doing virtual scrolling (it pulls the new set of rows only when user scrolls down)
Since you mention scrolling is very slow, the performance issue seems to be around rendering the new rows - you may try a couple things to improve performance:
1) remove autoHeight attribute. Instead, specify a fixed height in the style attribute
2) in the formatter function, instead of returning a dijit, try returning a simple html button/anchor styled as button
so remove the type:dojox.grid.cells._Widget attribute and in the format function return the html you want to use