I'm learning backbone.js to add some interactivity to an existing web app. On initial page load I'm bootstrapping some initial data into the page, using the reset() method suggested in the docs. This works great. I can also create new model instances, and the view handles them just as I would expect; they show up alongside the initial data, and everything is fine. (The new data also hits the database just fine.)
However, if I click on a link to a different page (not using backbone routes or anything, just a normal link) and then hit my browser's back button, the new models I created previously are gone; only the old initial data shows up. I've done some debugging and found that the reset() method runs each time the page is loaded, so presumably that's what's nuking the additional data I'd added. (However, if I actually refresh the page, the new data will be displayed again, since now it's getting bootstrapped in too.)
I know I could use fetch() to get the newly-added data (along with the older data), but I'm trying to avoid that, both because (a) that's an extra request every time the page is loaded, and (b) because the docs say that's not ideal.
So, what should I do so that using the back button doesn't make stuff (temporarily) vanish?
Page loads models, views, collections and Routers. Page set's up the collection through reset(bootstrapping). User clicks link to navigate to another page, clicks the back button. Something interesting happens now,
Routers match the url before the page is loaded ( when clicking back button). During this match you must verify that the collection contains new data and then do collection.fetch().
This will make you get latest always and hit the server only once (Either your collection is empty or it does not contain fresh data)
Related
I have a single page angularJS / nodejs / express app. When first loading the app, it pulls data via API from database and displays in a table in the 'home' route. 5 minutes later, it updates the data by doing the API call again then $scope.$apply().
After the update if I navigate away from the 'home' route to a different view within the app, then back again, you can see the old data for a fraction of a second then the new data pops into place again.
This will happen repeatedly as I navigate away and back to the route.
It seem like the browser is saving the old data, then updating it every time I go back.
Why is this happening and how can I make the $scope.apply changes permanent?
The solution was to load the data into an object in a factory, and update the data object in the factory instead of in the controller. This keeps the data up to date when changing views.
I have a simple app built with AngularJS routes which is loading the controller and template for each path. I have a register form and login form on separates paths/templates. Say I go to the login form (/#/login) and enter my username/password, if I then hit "Register" (redirects me to /#/register), and then I hit back in my browser, it will return me to /#/login but the form will now be empty; the information I typed in has been removed.
Expected behaviour would be that the form data is still there.
Anyway to make that happen (without manually caching the data in a service)?
I'm guessing when the page changes, Angular is tossing the old template data and reloading the template again. Is there a way to instead cache that page template/DOM and reload it when the user returns to that path (instead of downloading and showing new template file)?
Well, this is a bit tricky. The browser should implement this kind of feature out of the box. Firefox started doing some work around this "issue" but I don't really know the current status of it.
Alternatively you can use a bit of javascript with LocalStorage to make this works. You're using AngularJS you can create a Directive that encapsulates this feature to be used on multiple places.
Basically you need to create a mechanism that translate an field to and unique-identifier and a value. Every time the user type on the field, you update the store. If the user "finish" the interaction on the form, you clean the value from the store.
You can also grab a jQuery plugin and just create a directive that uses the plugin.
https://github.com/kugaevsky/jquery-phoenix (never tested it).
TL:DR
There's nothing you can't do using a DOM property/attribute or something similar.
You'll need to get your hands dirty on some javascript to make this happen.
I'm building a UI using AngularJS that consumes a REST service:
Here is the Server API
/items/ GET
/items/:id GET
/items/ POST (to create new item)
/items/:id PUT (to edit item)
/items/:id DELETE
What are the best practices when setting up the routes in Angular? These routes would map to the server REST API, but obviously there is a problem. I'm guessing I would need the action as part of the URL, right? Something like this:
Angular Routes:
/items/
/items/:id
/items/new
/items/:id/edit
/items/:id/delete
However the above pattern also has a problem. /items/new will match both /items/:id and /items/new so what is the best practice when setting up a route for create?
Also keep in mind that the client side, Angular, routes you're defining could be dependent on your UI. The routes you've defined are more like a traditional web application where you click an "Add New" button that takes you to a new page that has a form that you fill out. However, this may not be the pattern you use for a Single Page App (SPA) as is often created with Angular.
By this I mean that most of the SPA apps I've done don't actually have a standalone "/items/new" route on the client side. Instead, the "/items/new" functionality is handled on the "/items/" route/partial ("page" in traditional web app terms). This page lists the existing items, and there is a form on this page that you can fill out to create a new item. Or, there is an "Add New" button on this page (just like a traditional web app); but, clicking it either slides in a modal form or ng-shows a form that is already defined (but initially hidden) on the /items/ partial template.
Upon submission, the controller hits against "POST /items/" on the server to create the new item, updates scope with the return value from the POST (assuming success, this would be the new item info), and clears/re-hides the "new" form.
Bottom line -- keep in mind that in a SPA you may not actually need a "/items/new" if the UI is such that the new is handled as a capability of the item list page. Of course, if you're needing it to be a standalone page as an addressable endpoint (i.e. you're planning to link to this from multiple places, not just from within the app), then you'll obviously need a direct route.
In our case, we typically don't need a named route for it in our apps and we just have it serviced as a capability of the "/items/" route.
Using UI-Router we can setup client side routing.
Make sure you disable html5 routes, because some browsers still doesn't support html5 and they hit the server api instead of hitting the client route
You can do this by setting $locationProvider.html5Mode(false); in app.config method while defining angular app
/items/ - this is for listing items
/items/{id:[0-9]{1,4}} - this is for displaying one item in detail
/items/add - for displaying new item form
/items/:id/edit - for displaying existing item in Form for editing
/items/:id/delete - **This is not required, I mean you just hit the API when
use clicks delete, we cant show any deletion form**
You can use regex for params '/items/{id:[0-9]{1,4}}' this means allow only numbers 0 to 9 and 1 to 4 characters long
I'm building a wizard-config app with 3 pages. Each page has the same MasterController but different html templates. Each html templates has a different controller, say ControllerOne, ControllerTwo, and ControllerThree.
I load the data via MasterController and I'd like the data and any changes the user makes to be stored temporarily until the save & finish step on the final page. Trouble is as the user goes through the pages, MasterController is called each time and each time it fetches the data and overwrites the user's changes.
I've thought about attaching this data to a service or rootScope but the data initialization still happens in MasterController so the data would still be overwritten when each view is loaded.
Any advice on how I should go creating this functionality or restructuring my app to support this?
EDIT:
To be clear on the service issue. I don't know where to initialize it. If I do it in Controllers 1,2 or 3 my data is reinitialized each time the view changes so that doesn't work. I can't do it in app.run() either because I need to get to MasterController in order to get the necessary ID to make my HTTP request. I can't do it in MasterController because that too is called on each page switch.
Ideally I'd have a view within a view so that only the inner view changes. However angular does not support nested views and I'm trying to find a way around this without having to use angularUI.
To get around the data being loaded from the server on each page change and overwriting the user data, I used an "extend" function (like jQuery's) to extend the server data with the user data on each load. Page changes would call my service(that stores the temporary data) to save the data there and the final "save and finish" button would push the data in the service to the server.
We have a problem in updating the data lists on dashboard page after creating a new list in create page. It already saved on the database, but not updating in the views. It updates once i click the refresh button on the browser but this is a one page web app. How can I update the lists on my dashboard page after adding a data from the previous page without refreshing the page? I used couchbase for database.
The problem here is that you are loading the content from your persistent storage, and then it's in angular as-is, and to retrieve any updates you will have to re-fetch it from your persistent storage. Unfortunately, it is not as simple to $watch your back-end.
You have some options here: if you are making your change from within the angular component of the site, then you can just call a function when you are creating a new page which re-fires your db-access code, and refreshes the model.
If you are making changes from outside of angular, then you will need to either use polling to refresh your angular model periodically, or go for a fancier web-socket option, as explained here.
After reading this question and your other question, my guess would be, that you get the old view from couchbase.
Per default couchbase sets the stale parameter to update_after, which results in getting the updated view only after the second access, see the couchbase documentation for more information.
To fix this, it should be sufficient to set stale to false.
If you access couchbase via REST call, adding ?stale=false to the call should do the trick, otherwise add the parameter according to your used SDK specification.