ExtJs 4 - Copy records from store to treestore (grid to treegrid) - extjs

First of all: I'm using ExtJs 4.2.1
I have two grids: the first one collects records from a database (countries) and the second is a treegrid (should show countries and each country should expand a list of cities).
The behaviour I'm trying to achieve is that once you select a record (or multiple records) on the first grid, those records are copied to the treegrid as leafs so then I can fill those leafs with more records (cities).
I get the records from the first grid with:
grid.getSelectionModel().getSelection()
But I don't know how to copy them on the treegrid. I've tried using setRootNode and I can see the records on the "raw" property of the root node but I'm not able to show them on the grid.
What am I missing?
Updated: I've manage to get the countries with:
var records = grid.getSelectionModel().getSelection();
treegrid.getStore().setRootNode({ root: true, expanded: true, children: records})
Now I'm having problems to load the subrecords. As a test I've tried using the same "country records" to make sure there's no conflicts with the model. This is what I've tried:
var records = grid.getSelectionModel().getSelection();
for (record in records){
records[record].expanded = true;
records[record].children = records;
}
treegrid.getStore().setRootNode({ root: true, expanded: true, children: records})
This should show a list of countries and when expanding one of the records, it should show again the list as children of the selected record. It's not working :(

Solved it. I didn't liked the solution so eventually I constructed the whole thing on the backend but it was working.
Using insert/appendChild as Reimius said wasn't working since my records were not nodes so I had to loop over the country array and make each country a node with createNode(). For every country node I created, I looped through its cities, created a node for each one and then used insertChild() to associate it with the country.
Once everything was done I used:
treegrid.getStore().setRootNode({ root: true, expanded: true, children: records})
With "records" being an array of this monstrous creation of nodes.

Related

How to update autoGroupColumnDef property of ag-Grid after table is initialized

I have an ag-grid table (Enterprise version: 22.1.0) which is grouped using autoGroupColumnDef property. The grouping is dependent on the table's data and the data loads on a button click. I need to update the autoGroupColumnDef property's field name (_this.colName in the below code) after the page is loaded, right before loading the data.
Table's grid options:
_this.gridOptions = {
defaultColDef: {
sortable: true,
resizable: true,
filter: true
},
columnDefs: _this.columnDefs,
rowData: [],
enableRangeSelection: true,
autoGroupColumnDef: {
headerName: "Sector",
field: _this.colName,
cellRendererParams: {
suppressCount: true
},
tooltipValueGetter: function(params) {
return _this.tooltipVal
}
},
suppressAggFuncInHeader: true,
enableBrowserTooltips: true
};
I update the variable _this.colName before setting data to the grid. I have tried the following options and none of them worked for me:
_this.gridOptions.api.refreshClientSideRowModel('group');
_this.gridOptions.api.refreshCells();
_this.gridOptions.autoGroupColumnDef.field = 'Column's Name'
Any help would be appreciated!
There is a good workaround for this. You can set autoGroupColumnDef, then remove and readd all row groupings. It will redraw the group column with the new name.
gridOptions.autoGroupColumnDef.headerName = 'new_name';
// Get current groupings
var colstate = gridOptions.columnApi.getColumnState();
var colstateclear = gridOptions.columnApi.getColumnState();
// Clear groupings
var x = 0, xcount = colstateclear.length;
while ( x < xcount ) {
colstateclear[x].rowGroupIndex = null;
x += 1;
}
gridOptions.columnApi.setColumnState(colstateclear);
// Reset groupings
gridOptions.columnApi.setColumnState(colstate);
I contacted ag-grid support and apparently this is a bug and they have it in their backlog with no ETA available for now. A workaround they provided was to use: https://www.ag-grid.com/javascript-grid-grouping/#showRowGroup.
This is not really a good workaround because the grouped columns are separated and makes the page feel cramped. Also there are some look and feel issues that keep popping up (Eg: empty space added before each column that increases with each grouped column. ie second column has 1 cm added before it, third column has 2 cm added before it and so on. I guess this was added to bring the grouped look in the group column but you wouldn't expect this behavior when the columns are separated.)
ag-grid's backlog ID for the ticket: AG-3359 - Allow the autoGroupColumn to be used in the API calls for columns, at the moment there is no way to dynamically change it after creation. (ie, setColumnDefs …)
Link to track the progress: https://www.ag-grid.com/ag-grid-pipeline/
there is a straight forward method to update the autoGroupColumnDef object and its properties with setAutoGroupColumnDef
this.gridOptions.api.setAutoGroupColumnDef(<ColDef>{
...this.gridOptions.autoGroupColumnDef, // preserve the other settings except the ones you need to change
minWidth: 500
})
if any problems with the spread operator,
do it manually:
this.gridOptions.api.setAutoGroupColumnDef(<ColDef>{
// ...this.gridOptions.autoGroupColumnDef, // preserve the other settings except the ones you need to change
headerName: this.gridOptions.autoGroupColumnDef.headerName,
minWidth: 500
})
and one more thing, add this if you have any visual bugs, like: header row gets resized but bellow rows stays the same as previus state, so the refresh of model is required:
this.gridOptions.api.refreshClientSideRowModel();
this refresh is not ideal solution, because it refreshes everything, so you will loose expanded levels for example, still no clue how to preserve all settings.
https://angulargrid.com/angular-grid/client-side-model/#refreshing-the-client-side-model
and best solution for now is tu use:
this.gridOptions.api.redrawRows();
it keeps the rows expanded if are, checkbox selected if is.

Get current Sort Key Of Backgrid Table

I have following table made by Backgrid.js:
this.grid = new FixedWidthGrid({
columns: this.columns,
row: SelectableDocumentContextMenuRow.extend({
contextMenu: ContextMenuHelper.onRightClick
}),
collection: self.collection,
header: FilterHeader,
contextMenu: ContextMenuHelper.onRightClick
});
Now, when I click on a header label, the entire table gets sorted by that attribute on the client.
How can I get the current sort key/attribute (e.g. name, age etc.) of the collection?
If you are using backbone.paginator you should be able to get this by checking the value of collection.state.sortKey

Sencha Touch background syncing of store

I have a list that is bound to a store. I have a input text field (think chat like UX), and when the user clicks on a button, I do:
var newMessageData = {
text: textMessage
};
var message = Ext.create('MyApp.model.Message', newMessageData);
messagesStore.add(message); // At this point, the message shows up in my list
message.save(); // On a successful save, an identical message shows up again in this same list
How can I implement this, so the message only shows up once at first (immediately after the user types in something) and then the record itself just syncs with the server in the background.
Help is much appreciated! Thanks!
Edit:
My model definition is pretty simple with simple fields and a few converted fields + a custom idProperty:
idProperty: 'objectId',
{
name: 'objectId',
persist: false
}
You should be able to use messagesStore.sync() which:
Synchronizes the Store with its Proxy. This asks the Proxy to batch
together any new, updated and deleted records in the store, updating
the Store's internal representation of the records as each operation
completes.
http://docs.sencha.com/touch/2.4.0/#!/api/Ext.data.Store-method-sync
Okay, so what was missing was that I had to add the keys "primaryKey" to my hasMany and belongsTo relationships. In my case, I had idProperty: 'myCustomId', but that alone didn't work for associated models. I had to add primaryKey: 'myCustomId' to my hasMany and belongsTo relationships.

How to get only deleted records from an Ext js Grid store?

I have a grid store and I am able to get modified data using
var modifiedData = store.getModifiedData();
Now I want to get deleted records (I am using ExtJs 3).
I tried using var deletedData = store.getRemovedRecords(); but I guess this property is available in ExtJs 4.
I just want to fetch the records that are deleted from the grid.
Any help would be appreciated.
By default this is not possible.
ExtJS 3.x is only capable of tracking modified records (out of the box). Deleted (removed) records get removed completely. But there is one thing you can do; The store will fire the remove event for each record with the record itself as second argument. You may use this to create your own array of removed records. The implementation would be really simple I guess. You can do it per instance or create a whole new storetype by extending. But I guess the later is not really needed here.
Here is a example. Note that you might need take care of other events to clear the removedList.
var myStore = new Ext.data.Store({
removedList: [],
listeners: {
clear: function(store) {
store.removedList = [];
},
load: function(store) {
store.removedList = [];
},
remove: function(store, record, index) {
store.removedList.push(record);
}
}
});
Check these two links out. They might be helpful.
http://www.sencha.com/forum/showthread.php?58888-Store-find-deleted-added-records
mi
http://www.sencha.com/forum/showthread.php?15671-Ext.data.Store-with-persistence

Showing a limited subset of (or individual record from) a store in an Ext.DataView

In Sencha Touch, I often need to have an Ext.DataView panel that contains a small sub-set records or even a single record from the collection in the store.
For example I might have a Model for Car which has thousands of car records in it's app.stores.cars store but I want to show a smaller subset of these items (say; just sports cars) in my listOfSportsCars DataView while also showing the larger complete set of cars in my listOfCars DataView.
My first thought was to use multiple stores. So I'd have one main store for the big list of all cars, and a second store with a filter for my subset of sportscars. However, now updating a model from one store does not automatically update the record in the other store, so this defeats the purpose of using a DataView as the changes are not updated everywhere in the page when updating records.
My second attempt was to overwrite the collectData method on the DataView, which sounded exactly like what I was after:
var card = new Ext.DataView({
store: app.stores.cars,
collectData: function(records, startIndex){
// map over the records and collect just the ones we want
var r = [];
for( var i=0; i<records.length; i++ )
if( records[i].data.is_sports_car )
r.push( this.prepareData(records[i].data, 0, records[i]) );
return r;
},
tpl: new Ext.XTemplate([
'<tpl for=".">',
'<div class="car">{name}</div>',
'</tpl>'
]),
itemSelector: 'div.car'
});
A full example can be found here.
But, although it's documented that I can/should override this method, Sencha Touch really doesn't like it when you mess around with the length of the array returned by collectData so this was a dead-end.
How do others deal with displaying/updating multiple collections of the same records?
UPDATE There was a bug preventing collectData from working as expected. The bug has since been fixed in Sencha Touch 1.1.0.
As written in the comment:
I've used your democode with the last Sencha Touch release and opened all with Google Chrome. In the current version the error is fixed. (Version 1.1)
you could use Filters in order to get a subset of the data asociated to that store.
yourstore.filter('name', 'Joseph');
Also you should define 'root' as a function so it will always return an array. Readers in sencha touch asume you're always going to get an array as response, but it's not true if you are having a JSON with a single entry, try something like this:
root: function(data) {
if (data) {
if (data instanceof Array) {
return data;
} else {
return [data];
}
}
The full code for the store could be like this:
YourApp.ViewName = new Ext.data.Store({
model: 'YourApp.models.something',
proxy: {
type: 'scripttag',
url: 'http://somerandomurl/service/json',
extraParams: {
param1: 'hello'
},
reader: {
type: 'json',
root: function(data) {
if (data) {
if (data instanceof Array) {
return data;
} else {
return [data];
}
}
}
}
},
});
Hope it helps.
I use the "filter" features in the Store. Not modifying the DataView (I use a List).
Here's a snippet where I will fiter out Programs with a catagory that fit's a regex. (I have Programs with a catagory field)
MyApp.stores.Programs.filter(function(object) {
var regex = new RegExp(filterValue, 'i');
return object.data.category.search(regex) >= 0; // found match
});
You can clear the filter like this:
MyApp.stores.Programs.clearFilter(false);
This will update the DataView (I use a List) immediately (it's amazing).
So within your filter you could just filter out sports cars, or cars of a certain price, or whatever.
Hope that helps...
For my understanding of Sencha Touch this is not the best approach.
If it can be still good for performance you shoud use a second "slave" store, with inline data (http://docs.sencha.com/touch/1-1/#!/api/Ext.data.Store) that you can populate automatically from main store with subset of information you want to show when an event occours on the master store, i.e. load event.
If you want to deal with just one store a solution I can imagine is to use an xtemplate with "tpl if" tag in the dataview where you want to show just some information
http://docs.sencha.com/touch/1-1/#!/api/Ext. to write empty records. Maybe, also better solution, could be to use a custom filter function inside xtemplate, in order to put a css with visibility hidden on the items you don't want to see.

Resources