eXTjS 3.3.1 LiveGrid store.each gives only buffered rows - extjs

I use ExtJs 3.3.1 because many extensions don't work under 4.xx
One of these extensions is LiveGrid.
I can't try but i suppose a simmilar thing happens with a 4.x buffered grid.
When i do a report of the lines visible in the grid only the buffered lines are returned, i reposition the current record but the loading of the rest of the records only happens after the reporting finishes. How can i get all the records ?
In an button handler i call toReport(grid).
toReport = function(grid){
var store = grid.getStore();
var view = grid.getView();
store.each(function(record) {
Ext.defer(function(){
index = readRow(store, record);
if (index % 10 == 0){
view.focusRow(index);
}
}, 500, this);
});
console.log(output)
}
readRow = function(store, record){
output = "";
for (var xlCol=1;xlCol<record.fields.length+1;xlCol++){
var veld = store.fields.itemAt(xlCol-1).name;
waarde = record.get(veld);
if (realTypeOf(waarde)==="date"){
output += waarde.format("d-m-Y");
}else{
output += record.get(veld);
}
}
console.log(store.indexOf(record)+ " " + output);
return store.indexOf(record);
}

The grid needs to manipulate its store filters, sorters, paging, etc., in order to obtain the records it want to display. The store itself only keeps in memory the subset of records that matches its filters, etc. That is the way stores are designed in Ext: they are intended to be bounded to one and only one view.
I think in your case, the simplest solution is to create another store with a similar configuration, and use its load method with params such that you get all the records.
If you're reticent to fire multiple requests for retrieving essentially the same data, have a look at Ext.data.Proxy. Unlike stores, proxies are not bound to a specific view or task and can be shared between multiple store instances. So in theory, you can create a proxy that requests all the records from the server at once, and then feeds a subset of them to multiple stores. For that you'll have to implement the doRequest method of the proxy (or most probably overrides the one of the proxy you're already using).

I did find a solution by using recursion.
Like this the view kan keep up with the enumeration.
Ext.toExcel = function(grid){
var store = grid.getStore();
var view = grid.getView();
readRow(store, view, 0);
}
readRow = function(store, view, index){
output = "";
record = store.getAt(index);
for (var xlCol=1;xlCol<record.fields.length+1;xlCol++){
var veld = store.fields.itemAt(xlCol-1).name;
waarde = record.get(veld);
if (realTypeOf(waarde)==="date"){
output += waarde.format("d-m-Y");
}else{
output += record.get(veld);
}
}
//console.log(index+ " " + output);
if (index % 50 == 0){view.focusRow(index);}
Ext.defer(function(){
if (index < store.totalLength){
readRow(store, view, index+1);
}
}, 100, this);
}

Related

'504 - Gateway Timeout' when Indexing the items in Episerver Find

When Indexing the items, it fails sometimes and it gives,
The remote server returned an error: (504) Gateway Timeout. [The remote server returned an error: (504) Gateway Timeout.]
The Indexing logic is here as below,
var client = EPiServer.Find.Framework.SearchClient.Instance;
List<ItemModel> items = getItems(); // Get more than 1000 items
List<ItemModel> tempItems = new List<ItemModel>();
//Index 50 items at a time
foreach(var item in items)
{
tempItems.Add(item);
if (tempItems.Count == 50)
{
client.Index(tempItems);
tempItems.Clear();
}
}
What causes this to happen ?
Note: The above mentioned ItemModel is a custom model which is not implemented interfaces (such as IContent). And the items is a list of ItemModel objects.
Additional info:
EPiServer.Find.Framework version 13.0.1
EPiServer.CMS.Core version 11.9.2
I always figured the SearchClient to be a bit sketchy when manipulating data in Find, as far as I figured (but I have to check this) the SearchClient obey under the request limitation of Episerver Find and when doing bigger operations in loops it tends to time out.
Instead, use the ContentIndexer, i.e.
// Use this or injected parameter
var loader = ServiceLocator.Current.GetInstance<IContentLoader>();
// Remove all children or not
var cascade = true;
ContentReference entryPoint = ...where you want to start
// Get all indexable languages from Find
Languages languages = SearchClient.Instance.Settings.Languages;
// Remove all current instances of all languages below the selected content node
//languages.ForEach(x => ContentIndexer.Instance.RemoveFromIndex(entryPoint, cascade.Checked, x.FieldSuffix));
foreach (var lang in languages)
{
if (cascade)
{
var descendents = loader.GetDescendents(entryPoint);
foreach (ContentReference descendent in descendents)
{
ContentIndexer.Instance.RemoveFromIndex(descendent, false, lang.FieldSuffix);
}
}
// Try delete the entrypoint
var entryTest = loader.Get<IContent>(entryPoint, new CultureInfo(lang.FieldSuffix));
if (entryTest != null)
{
var delRes = ContentIndexer.Instance.Delete(entryTest);
}
}
This is the most bulletproof way to delete stuff from the index as far as I figured.

ui-grid infinite scroll with row processor filtering

I have an angularjs app using ui.grid with the infinite scrolling module. I am using whole row filtering as described in the documentation like so:
function MyController($scope){
var that = this;
var getData = function(){
//logic left out for brevity
};
var onRegisterApi = function(gridApi){
gridApi.grid.registerRowsProcessor(function (rows) {
return that.filterRowProcessor.apply(that, [rows]);
}, 200);
gridApi.infiniteScroll.on.needLoadMoreData($scope, getData);
};
this.options["onRegisterApi"] = onRegisterApi;
}
//...code excluded for brevity...
MyController.prototype.filterRowProcessor = function(renderableRows){
renderableRows.forEach(function(row) {
if (this.selectedMap[row.entity["Id"]]) {
row.visible = false;
}
});
return renderableRows;
}
The idea is to filter out rows which have an Id belonging to a specific collection; which works as designed. My problem is that when I get my first page of data the filter row processor removes enough rows from visibility that my scroll bar disappears. This in turn causes the infinite scroll api to never raise the "needLoadMoreData" event.
Is this uncharted territory, or is there a way around this? I am also open to not filtering by that mechanism if its easier to do another way.
UPDATE (01/08/2016)
I have found a work around that I don't like very much. Essentially I have a known page size and if the data coming in to the grid is less than that page size and my callback returns false for "end of query", I automatically issue a next page query. I would rather find a solution via the grid api, but for now this will work.
if(this.itemsSource.data.length < constants.PAGE_SIZE && !continuation.endOfQuery){
//call get data again
}
After thinking about it for a while I decided on the below method as my solution. I am still open to suggestions if it makes more sense to do it a different way. Rather than relying on a length of data (which only loosely translates to having a scroll bar) I decided to calculate the height of the total rows visible, compared to the viewport of the grid.
//this method get called from the callback from needsMoreData
//hasMoreData is the same boolean flag sent in to dataLoaded
var shouldRetrieveMore = function (gridApi, hasMoreData){
if (!hasMoreData) {
return false;
}
var totalCountOfRows = gridApi.grid.getVisibleRowCount();
if (totalCountOfRows === 0) {
return true;
}
var height = gridApi.grid.getViewportHeight();
var heightOfRow = gridApi.grid.getVisibleRows()[0].$$height;
return ((heightOfRow * totalCountOfRows) <= height);
}
One additional addendum to the solution could be to sum the $$heights of all the rows, but I decided against it since in my uses they are always the same height.

How to count number of rows in sencha gridview?

I have a Gridview on my page and I'm using buffered store. Is there a way to get the visible number of row count. Thank you
Here is a sample code that you can try: (I hope you'll get some idea from this)
// The below condition has to be checked for each record
// record: record instance
var me = this; // grid scope
Ext.Array.each(me.columns, function (item) { // iterate through each column in the grid
if (item.hidden || !item.dataIndex) { // you can avoid hidden columns and one's that re not bound to the store
return;
}
var cellVal;
try {
cellVal = Ext.fly( me.view.getCell(record, item)).select('cell selector class').elements[0].innerHTML;
} catch (e) {
// handle if you want
}
if (!Ext.isEmpty(cellVal)) {
// this record has been rendered
}
}, this);
This will get you all the records that are rendered. Since you are using a bufferedRenderer, this will also return the records that are rendered but not in the view, you can check and put an offset for the buffer.
Note: I've a similar logic in working in ExtJs 5 but haven't tested in touch.

Firebase - Lazy Loading List of Data

I have a requirement where I want to display say the first 10 entries in a list and once the user scrolls down I would like to append the next 10 entries. I am currently using Angularfire and all the documentation specifies that I should not do array operations on a $FirebaseArray:
This array should not be directly manipulated. Methods like splice(), push(), pop(), and unshift() will cause the data to become out of sync with server.
So my options are to load the next 10 entries and:
Use $add(), which would write them to the server again (think this could cause some nasty recursion)
Use concat, in which case my data will get out of sync with the server
Get the list again but adjust the limit to be 20, which I think would cause all the data to be reloaded defeating the purpose of lazy loading.
Here is the code that initially loads the list (based on the Angularfire seed app):
var lastKey = null;
var firstKey = null;
$scope.messages = fbutil.syncArray(userMessages,{'limit':10});
$scope.messages.$loaded(function(data){
lastKey = data.$keyAt(data.length-1);
firstKey = data.$keyAt(0);
});
And here is the code that is triggered when the user scrolls down:
$document.on('scroll', function() {
if($(window).scrollTop() + $(window).height() > $(document).height() - 100) {
var newMessages = fbutil.syncArray(messagePath,{'limit':10,'startAt':lastKey});
newMessages.$loaded(function(data){
lastKey = data.$keyAt(data.length-1);
firstKey = data.$keyAt(0);
$scope.messages.concat(newMessages);// this is probably a bad idea
});
}
});
Based on Kato's comment the following is the best solution given the current API.
var limit= 10;
$scope.messages = fbutil.syncArray(messagePath,{'limit':limit});
And the scroll trigger
$document.on('scroll', function() {
if($(window).scrollTop() + $(window).height() > $(document).height() - 100) {
limit += 10;
$scope.messages = fbutil.syncArray(messagePath,{'limit':limit});
}
});

Extjs 4.2: How to set the value of grid

I have a grid for terminals, What I want to do now is to display the selected terminals into another grid. I am able to get the selected terminals with this code:
var sel = scope.getTerminalGrid().getSelectionModel().getSelection();
var user = scope.getProfinfo().getForm().getValues();
for(var i=0; i < sel.length; i++)
{
var terminals = sel[i].data;
}
You can simply get the data (in your case above its the 'sel' variable) and then load it in the second grid store.
Something like that:
var sel = scope.getTerminalGrid().getSelectionModel().getSelection();
var selRecords = sel.getSelection();
var secondGrid = scope.getMySecondGrid();
var secondStore = secondGrid.getStore();
secondGrid.removeAll(); //Clear the data
secondGrid.add(selRecords);
Of course, I separated all in a lot of variables, you can abstract some of them.
you can do it multiple ways, one is with a drag and drop grid group, another is grabbing the grid of second store like so .
var secondGrid = scope.getMySecondGrid()
secondGrid.getStore()
the store is the powerful underlying data structure of the grid. You can then load any data you want in there.

Resources