How to cache a page using AngularJS RouteProvider? - angularjs

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

Related

What's the right way to reset / initialize InfiniteLoader

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.

Changing states without reloading previous view data when I go back to it

I am new to angular and was wondering if I could somehow change states (after clicking on link from a list of search results) and load a new view, hide the old one (including header !), but not unload it/not have to request JSON data again if I got back to the search results for products view from the product details view.
Well, this will be a really short answer.
Take a look at this:
$templateCache You can play around with it so you won't need to reload pages when going back and forth.

Angularjs: how to pass entire object to another controller?

OK, I'm very new to AngularJS. I'm converting a rather rough-app (that I've been writing for a couple of days) from using mostly jQuery over to using Angular. [ I discovered Angular "mid-stream", while researching how to alleviate all the bookmark and back-button headaches I was running into.]
On my main page, I have a table of search results. (If the user arrives without passing any parameters, a default search is called to build the table. And, of course, they can use a search form on that page to show themselves a different set of results.)
Now, when the user clicks on a table item, I want that table to more or less "become" a drop-down menu on the Item Details page that can be used to navigate from one table item to the next. (The list will usually be less than 20 items long at any given time.) Same data, same sort order, just in a different control.
Rather than build that "Child" page so that (in addition to making Ajax calls to pull up the item details) it runs the exact same query AGAIN and then builds a drop-down out of it... I thought perhaps there was some more-efficient way to do it.
Perhaps, pass the entire object of objects from the search results on to the Details controller? (I would somehow have to also pass an id for whichever item the user actually clicked on for details as well.)
[With jQuery, I had been building both the drop-down and the table of results on the same page...and then just use show() and hide() to alternate which one I was displaying. And I would fetch the Item Details data and populate/show hidden details divs whenever a table row or drop-down option was selected.]
First I think you should use some kind of routing, maybe this can be helpful
https://github.com/angular-ui/ui-router
And second one, if you want to access same object with multiple controllers, you should use factory with your object, and all you need is to inject that factory into your controllers, and you will have access to the same object from multiple controllers. Here is the short tutorial, it's very easy to understand:
https://egghead.io/lessons/angularjs-sharing-data-between-controllers
And third option, but it's not nice, is to emit or broadcast event and send object from one controller, and in another one you can put a listener for that event, here you can find more information:
http://www.theroks.com/angularjs-communication-controllers/
http://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/

AngularJS watch not working in child controller

I'm trying to use AngularJS and Angular-UI-Bootstrap to create a WebApp but as I'm rather new with all this, I need some help. I'm using ng-repeat and an array to create a Tab interface.
Depending on an action in the first Tab, a second Tab is added to the interface or should be refreshed if it's already open. I've got the Tab working and have a check to make sure it isn't added again when it's already open.
The basic structure is the following: One controller (TabController) to control the Tab interface, and one controller (Tab1 and Tab2) for each Tab that's added to the interface.
Now, I have the following problem, the content of the second tab should change depending on data changed in the first tab. When the user confirms the data in the first tab, I execute a function in the TabController (to add / activate the second tab) that also changes some data in the scope. I can't seem to be able to detect the change in this data in de second tab, I've created a watch for the field, but it's only fired the first time the tab is loaded. If I use the field itself, the data is changed, but the watch doesn't fire. Anyone got an idea how I can get this to work? The data that changes should be used to make changes to other information, that's the reason I'm trying to use a watch and execute a function...
I've created a Plunker that should demonstrate in a simple example what the problem is and what I'm trying to do (I hope...)
DEMO
On the first Tab, there is a button to add a second tab (or activate it), as an example, I just increase a count that's displayed on both tabs. On the second tab, I have a local field on the scope that I fill with the global field using a $watch.
When starting the first time, the global count is one, after adding the second tab, both the global as the local count on the second tab are 2. When I go back to the first tab and click the 'Add tab' button again, the global count on both tabs is 3, but the local count on the second tab remains 2 and the watch isn't fired.
As I'm new to Angular (and web programming) I might be trying to do something that goes against all the best practices, so if someone has a better / different way to do what I'm trying to do, feel free to make any suggestions.
Your watch expression was incorrect, the correct expression would be
$scope.$watch("tabCount",
function() {
$scope.localCount = $scope.tabCount;
})
}
instead of
$scope.$watch($scope.tabCount,
The first one means you want to watch on a variable tabCountdefined over the scope.

Best way to implement in angularjs list detail view hierarchy without reloading when going back

i've the following hierarchy structure : Group -> Family -> products -> Product details.
each node is retrieve through an $http service.
i would like the user to be able to drill down until the final product details and i would also like no reloads when the user hits the back button as parents never changes.
i've succeeded to build the first part using routes and it works pefectly but now each time i want to go back the controller of the parent view (last view) is reloaded and i don't know how to avoid this reloading.
i am thinking of changing my way of doing it by having only 1 view (while 4 before) and manage the drill down through a directive, do you think it could be considered as a good practice ? how would you implement this ?
You could check out AngularUI Router, since one of its main feature is the ability to nest states & views.
Have a look at the UI-Router Demo, source code here.

Resources