I have a grid made with ExtJS, and I render it to a div that I define, when a refresh is requested I simply "empty" the div using JQuery and then re-render the grid creating new objects each time:
var grid = new xg.GridPanel({
store: store,
columns: [
...
renderTo: 'db-grid'
And then to empty the div I use this:
$("#db-grid").empty();
This works well for like 3 or 4 refreshes, and then it seems to load really slowly, I imagine this is because it re-creates all these objects again, the only thing that changes each time is the "store." I acquire that through an AJAX request, is there a way to refresh this without creating a new grid each time?
I'm pretty new to ExtJS, and I'm making a bit of a transition here from JQuery, which is why I'm using the "empty()" function from JQuery, if you know of a ExtJS alternative, I would be glad to use that instead,
Thanks!
Take a look at Store's load(Object options) and reload(Object options) methods at http://dev.sencha.com/deploy/dev/docs/.
An example of this functionality can be seen in Ext.PagingToolbar. This class contains a button that refreshes a Grid and its Store, without destroying the Grid each time:
// private
doLoad : function(start){
var o = {}, pn = this.getParams();
o[pn.start] = start;
o[pn.limit] = this.pageSize;
if(this.fireEvent('beforechange', this, o) !== false){
this.store.load({params:o}); // here is the call you're interested in
}
},
doLoad() is then simply called from the method doRefresh():
doRefresh : function(){
this.doLoad(this.cursor);
},
I included this code for the sake of a complete example, but really all you need to worry about is the load() or reload() methods. Make sure to read the API to see a full list of arguments that can be passed into the methods.
Related
I like the gijgo treeview with checkbox as its clean and neat and it solves the purpose of showing the hierarchy information. Check below link for documentation.
https://gijgo.com/tree/demos/bootstrap-treeview-checkbox
Since knockout.js is preferred for the front end development hence its needed to develop a knockout binding for this particular requirement.
The idea is to populate the hierarchy data from the backend and bind it to the custom knockout binding.
The user selects/un-selects some checkboxes and then hits the save button. the selected/unselected data is again sent back to the server for the save.
The below code is the usage of the control in jquery.
The function tree.getCheckedNodes() returns the array of selected checkboxes.
How would one call the above function from an knockout binding.
ko.bindingHandlers.tree = {
init: function (element, valueAccessor, allBindingsAccessor) {
},
update: function (element, valueAccessor, allBindingsAccessor) {
var options = valueAccessor() || {};
var value = ko.utils.unwrapObservable(valueAccessor());
var tree = $(element).tree(value);
}
}
In the init method:
Unwrap the widget's initial data passed by your viewmodel from the valueAccessor
Convert the initial data to the format the tree widget understands
Initialize the widget with the correct settings $(element).tree({ /* ... */ })
Attach an event listener (.on("change", function() { }) to track user-input
In the event listener function, write back the data from the UI to the viewmodel (e.g. valueAccessor() (tree.getCheckedNodes()))
Optional: add custom disposal logic to clean up the widget if knockout removes it from the DOM
In the update method, which is called if your view model's value changes
Implement the logic that updates the widget based on your new settings. Probably something like tree.check(ko.unwrap(valueAccessor())). Make sure the update is "silent", if it would trigger a change event, you'd end up in an infinite loop.
I need a way to get all rendered rows in a treepanel, but I was not able to find how to achieve it.
I tried the following events:
treepanel#render: panel.getNodes() is empty, because the rows get rendered after the panel.
treeview#refresh: it gets called later, and view.up('panel').getNodes() successfully returns the rows
But this does not take into account the rows added later by expanding the nodes.
treeview#cellclick: this could almost work together with treeview#refresh, but it does not account for programmatically .expand() a node
treepanel#itemexpand: gives access to the expanded node and the row HTMLElement, but what I need are the children that are rendered
I also tried the renderer in
xtype: 'treepanel',
columns: {
xtype: 'treecolumn',
renderer: function (...)
This is the best candidate in that it is called exactly once for each rendered row, but the problem is that it is called before the row is rendered, so there is no way to get a reference to the rendered row from it.
The same problem applies to gridpanel, but there things are even more complicated. Among other problems, I was not able to find an event that triggers when a bufferedRenderer renders new pages of the store.
I was not able to find a solution using the inconsistent events of ExtJs.
Fortunately, in vanilla JS, there is a possibility to get nodes that are inserted to the DOM: MutationObserver. This is what I came up with:
Ext.define('Mb.Application', {
...
launch: function() {
const body = document.getElementsByTagName('body')[0],
config = { childList: true, subtree: true },
callback = function(mutationsList) {
mutationsList.forEach(mutation => {
if (mutation.type !== 'childList') return
if (!mutation.addedNodes.length) return
mutation.addedNodes.forEach(node => {
// test if it is a row and do what I need
})
})
};
var observer = new MutationObserver(callback.bind(this));
observer.observe(body, config);
I'm not aware of the performance impact this could generate. In my case there was none noticeable.
I don't know if this will help someone, but just in case I share it...
I'm using Sencha Touch 2 and wonder how I listen to the Store's refresh event in my Ext.dataview.List? I want that my list automatically updates when there are new records in my store, so the refresh event seems to do the job for me, but how do I set up a listener?
Edit: Thanks to Anand Gupta I realized my problem isn't refreshing the list but just displaying it. So I will give you some more information and hope you can help me. I use NavigationView inside tabpanel. I have one list loading from localstorage which works just fine, if you tap disclose indicator you come to a form with a button "auto complete".
By tapping autocomplete the following method is called:
e.stopEvent();
var lastname = this.getNewUserForm().down("textfield[name=lastname]").getValue();
if(lastname!=="")
{
var complete = this.getApplication().getController("Complete");
this.getUserNav().push(complete.getView());
complete.setSearch(this.getNewUserForm().down("textfield[name=firstname]").getValue(), lastname);
}
else
{
//errormessage
}
The getView() method is a ref with auto create and the "setSearch" Message on Complete Controller simply loads the Store through jsonP Proxy:
var store = Ext.getStore("Playernames");
store.setParams({firstname:firstname, lastname:lastname});
store.load({callback: function(){
console.log(this);
}});
I added a log to see that the store is properly loaded and store is properly loaded.
Thanks for help
Ok after some more hard search I found my bug: I had a List view embedded in a Panel with an undefined layout. So I changed the layout to "fit" and it works fine.
I have a Panel with multiple grids. I'm trying to make some kind of global refresh button by which I mean, a button that will refresh all the grids and open tabs, without losing data like when F5 is pressed.
With two of the grids it was easy just get the store and load it but the third one makes a problem. When I try the same as with the previous two which works OK I get URL is undefined.
Here is my code:
reloadInstructionsStore: function() {
var reloadInstructionSt = this.getStore('Instructions');
var activeCat = this.getActiveCategory();
reloadInstructionSt.clearFilter(true);
reloadInstructionSt.filter({
filterFn: function(item) {
return item.get('category_id') == activeCat;
}
}),
reloadInstructionSt.load();
},
The only reason I can think of is that the store that I use here is defined different from the other 2. It's not with PROXY and CRUD, but looks like this:
Ext.define('MY.store.Instructions', {
extend: 'Ext.data.Store',
model: 'MY.model.InstructionRecord',
autoLoad: true,
data: g_settings.instructionsApi.initialData
});
Is the problem here and is there a way to make things work even like this?
Thanks
Leron
You do not need to reload this store, the data is provided on initial page load. The variable g_settings.instructionsApi.initialData tells me that the data is available as static on the page. All you need to do in this case is reset the filter, and just remove the reloadInstructionSt.load(); call.
If you actually do want the data to reload from the server, you will need to give your store a url that it can get the data from and the server will have to be able to serve this data up.
I wonder why ExtJS developers decide to remove reload() method in ExtJS 4 Store API. I think it's a bad decision.
Here is my problem. I'm using the following code to initialize a grid's store:
store.load({
params: {
paramName: dynamicParameter
}
});
NOTICE the dynamicParameter variable in the code above.
Then, if I delete some records from the grid, I need to reload the store.
The problem is: the code segment which reload the store should not know the dynamicParameter value.
The code to delete records is like this:
function deleteGridItems(grid, deleteUrl){
// get selected rows
var records = grid.getSelectionModel().getSelection();
// ...... (codes to send request for deletion is ignored) ......
if(success){
grid.getStore().reload();
}
}
Unfortunately, the grid.getStore().reload() above will be an error because in ExtJS 4, reload() function doesn't exist anymore.
So how to reload the store with the same parameter??
Thank you.
If I'm not mistaken load() function now does exactly the same as reload() before. Try it.
you need to set proxy extra params instead specifying it each time on load():
see this http://www.sencha.com/forum/showthread.php?127673-Reload-Store-in-EXT-JS-4
Also note that Ext JS doesn't appear to check before loading whether the store is already loading data. I'm not sure why this is, but it can be fixed by overriding the load() method in a Store or TreeStore.
load: function(options) {
// Loading quickly will cause data in the panel to break
if (!this.isLoading()) {
this.callParent(arguments);
}
},
I haven't experienced issues with grids, but with trees if you press the refresh button very quickly you sometimes get an error and the tree structure breaks:
Uncaught TypeError: Cannot read property 'internalId' of undefined