What's the right way to reset / initialize InfiniteLoader - reactjs

I'm trying to use InfiniteLoader from the react-virtualize library to show up a scrollable list that has a textSearch input field on top (used to filter list entries).
The code I use is very close to the InfiniteLoader Sample Code.
The list is working fine, but I'm not sure how to reset/initialize the InfiniteLoader when the searchText is changed and (completely) new data should be shown.
The flow is like this:
the list is opened for the first time and shows data from the redux store (works fine).
user changes textSearch and new data is fetched to the store
at this point, InfiniteLoader should be be initialized (I tried calling resetLoadMoreRowsCache on InfiniteLoader)
InfiniteLoader should call loadMoreRows like for the first time and rerender with the new data
I've seen that the INFINITELOADER DEMO has the same behaviour: by clicking 'Flush Cached Data' nothing happens until I start scolling the list.
So my question: what is the right way to reset/initialize?

For newer versions of InfiniteLoader
Since this question has been posted, InfiniteLoader has gained a parameter which auto-reloads the data. You can now use:
infiniteLoaderRef.resetLoadMoreRowsCache(true);
to automatically flush the cache and get new rows.
For older versions of InfiniteLoader
InfiniteLoader reacts to a range of rows being rendered. The resetLoadMoreRowsCache method just resets cached data. It doesn't automatically request a batch of rows be loaded.
Arguably it should. I don't know. It seemed easy enough for user code to auto-load the first batch of new data if the application state has changed in such a way as to require resetLoadMoreRowsCache to be called.
Anyway, tl;dr is that you should be able to do this:
infiniteLoaderRef.resetLoadMoreRowsCache(); // Reset the cache
loadMoreRows({ // Manually kick off the first batch
startIndex: 0,
stopIndex: 20 // Or whatever
});
Happy to review a PR to change the default behavior if you feel it could be improved.

Related

How to persist selection on React using mui-datatable

I'm using mui-datatable to implement table in my app. I've every feature I need up and running, and I'm using server side data and pagination.
The problem is that I need to persist selection of rows when the user change the current page.
I can store the ids of the rows that where selected in an external array using onRowSelected.. but I'm not sure how to make the table render those rows as selected when user changes the page.
Bare in mind i'm using server side data, so the idea would be that in page 1, when I select row 1, a take the id of that record and add it to the array of selected ids. Then I need to check if the ids of rows that are currently displayed in the page are included in the selected array, and if so then check it as selected in the table. That way when I change the page, the same logic would run and all rows would be cleared since none of the row in the new page are selected.. I think you get the point.
I dont know where should i check if the row's id is included y my selected array and if so, how to check it in the datatable.
Thanks in advance for the help.
You can wrap your entire MUI datatable in another component which maintains the state of all selected rows
I'm stupid... I just needed some sleep xD
My problem was solved once I realized that I just needed to pass the rowsSelected option like this:
rowsSelected: this.state.pictures.filter(p=>this.state.selectedIds.includes(p.id)).map((p,i)=>i)
where this.state.picture will change when the user changes the page and rowsSelected will also changed.
Never mind... It's a rookie mistake.

React+Redux+Asynch: data loading cascade, start the following after the previous complete

Having not much experience in ReactJS currently trying to solve components cascade loading. Let me explain use case on an example.
Assume we have 3 comboboxes - Author, Book, Library.
Something triggers loading Author data -> When data is loaded, the first found author is automatically selected and is used as search criteria for the second combobox(Book) -> When all books of the selected Author is loaded, the first found book is selected. The selected Author and Book are used as search criteria for the 3rd combobox(Library) - after library is found select the first in the list.
Data is loaded using 'cross-fetch'.
Internal component is built from 3 "Select"(comboboxes) controls. Initially, an internal
implementation of 'Select' React control is used but the flow was
checked with react-select library as well. In both cases the
initialization of comboboxes looks similar:
<Select
options={authors}
value={selectedAuthor}
onChange={this._authorChanged}
/>
react-redux#connect maps state to props
So the questions is:
how properly and what is a proper place to catch "data loading is complete" events so that the next planning loadings may be initiated?
What I did/thought about:
I can detect in render() method that it is time to start the following data loading but as I learned it is not a good solution(we better not to do any operations other than required for rendering inside the method).
Theoretically, I can build loading chain from my actions but at the moment I do not like the idea as:
despite load method is currently used only for the initializaion of combobox later I want to reuse it in other places where next loading is not needed;
currently for me this does not look consistent when data load is not fired by ui events
I thought setting default selected value value={selectedAuthor}
during initialization would fire onChange event but it seems not true(at least in my case).

How to cache a page using AngularJS RouteProvider?

I have a standard Master > Details page in AngularJS setup using RouteProvider.
The Master page has a variation of "infinite scrolling" where Data can be added AND removed at both ends. Say, the user is looking at Contacts list, and has scrolled to 312th entry of the Contact List, only Contacts numbered 200-400 are kept, and the entries 1-200 are removed from Scope. Of course, when the user scrolls DOWN beyond 360, the list is appended with 401-500. And if the scrolls UP above 240, the list is "pre-pended" with 100-199.
Now, the user can click on a particular Contact and go to the Details page. Upon pressing 'Back' (window.history.back) how do I make the Master page re-render with,
Exact list 200-400 as it was when the page was left
Scrolled exactly to the position 312
(IMPORTANT) Listeners still listening correctly for scroll events beyond 360 or above 240?
Is this even possible? And if yes, please help me with how.
I'm not going to write code for this, it's a bit difficult without a deeper understanding of how your infinite scroll works but will offer some ideas
The first thing you would need would be to store the view state in a service and for more robust persistence ( page reloads or return visits) in localStorage synchronized with the service.
The main start point for the view state would be a start index so you know what to filter in your data array ... and either a length value that may or may not be constant in your app or an end index.
As for the scrolling you could use a scroll event handler in a directive to update the service object with offset scrollTop value in order to set on subsequent visit.... angular.element(containerElement)[0].scrollTop = service.scrollTop as a loose example
There is also $anchorScroll service that you could use by setting ID on each item
This won't give you a full solution but hopefully can get you started
Note that you will need to account for time it takes to render ng-repeat by defering to next digest cycle before trying to set scrollTop if you use that

ExtJS 3.4: Grid does not automatically save and restore state. What am I doing wrong?

I have an Ext 3.4 grid with stateful:true, a stateId, and each column in the column model has an id.
Yet when I resize columns I don't see any state cookie saved, and the column widths are not restored when the page is reloaded.
I do have a state Manager with cookie provider defined and I can set/get cookie values via the state manager just fine.
I also added handlers for beforestatesave and statesave and they are being called, but still - no cookie is saved and no state restored. Those handlers are being passed the correct arguments as well - the columns argument show correct updated widths when dumped into the console.
My question is: am I doing something wrong? Should I not expect this to be automatic?
Do I actually have to use those state events to manually save and restore state?
I ran into this problem myself and I figured it out only after about 2 hours of hair pulling.
Do you happen to have a rather large grid? If the cookie data exceeds 4k, which it will easily do if you have 20+ columns of data, it will not save. It will not error either.
I suppose the only other option here would be to go to a different state provider. I'm going to look at the httpProvider that Saki has graciously provided as an alternative.
EDIT:
I've tried to override the provider and remove the string escaping when saving the cookie. This reduces the size by about 50%. I cannot seem to consume it when trying to restore though. I'm certain that the Ext authors were doing this for a reason, otherwise it wouldn't make sense because it inflates the cookie by so much. So much for a hack.
To make a GridPanel stateful I just added stateful: true to the config and setup my provider right before I create any objects
Ext.state.Manager.setProvider(new Ext.state.CookieProvider({
expires: new Date(new Date().getTime()+(1000*60*60*24*30)) // 30 days
}));
I've not tested if it remembers width but try moving columns and the sort order and see if they are being remembered.

ExtJS Store/Grid reset

I have a button that when clicked, will create a JSONstore using a url provided. The store is then loaded into a grid. If the button is clicked again, it adds all the information again (so it is listed twice). I want it so that when the user clicks the button, it clears the store/grid and then adds everything.
Any ideas on how to accomplish this?
Thanks,
EDIT
ExtJS 3
datasetStore.removeAll();
datasetStore.loadData(datasetsArray);
It will be useful to see some code examples (and extjs version), but you can simply use loadRecords method (http://docs.sencha.com/ext-js/4-0/#!/api/Ext.data.JsonStore-method-loadRecords):
grid.store.loadRecords([array of your new records here], {addRecords: false});
{addRecords: false} indicates that existing records will be removed first.
for ExtJs4: simply doe store.loadRecords([ array ]). In version 4.2.2 the store.proxy has NO clear() method so that doesn't work (was proposed in other examples elsewhere...)
If you want to to totally clear store and proxy, pass an empty array. This is handy because in some cases you want to clear the store and removeAll only moves the data to an array managed internally in the store so when later doing a sync on a gridStore which shows only 1 record, you may see your controller flooded with a bunch of records marked for removal!!

Resources