I have read Ember docs related to Substates etc and I understand how it works. In my current application my loading.hbs and other child loading.hbs templates work fine.
I just want to discuss a use case.
In my route A, in my model function I do fetchAll for my model.
I go to Route A, First time api request is sent and I see my loading screen.
now I navigate to some other route B.
now I come back to first route A, api request is sent again but this
time loading screen is not shown.
I want to develop my understanding here. Now the second time loading screen is not shown which tells us that store had data so there is no sense to put it on loading and after fetch store sent request to sync with backend.
QUESTION
Now I want to know if this is a default behaviour of Ember with Ember-data?
To show this loading screen, will I have to do something manually?
Ideally what I want is, if on second request data was fetched then show it and at the same time show loader to tell user that it is syncing with backend as well.
I know everything can be done manually, I don't want to reinvent the wheel or do things in non-conventional way. So I want to know best optimized solution for this as provided by Ember which an experienced Ember developer can help me understand.
Thanks in advance.
Now I want to know if this is a default behaviour of Ember with
Ember-data?
Yes, that's the default behavior of Ember data when you do a findRecord or findAll where shouldBackgroundReloadRecord or shouldBackgroundReloadAll event of the adapter respectively, is defaulted to true. You can turn this off by returning false and ensuring shouldReloadAll or shouldReloadRecord respectively are set at true to ensure the request always hits the API and not fetches from cache.
Ideally, showing data immediately on the screen is always advisable as it has a better UX in terms of giving the user a feel that data is already there and that some parts of the data is being fetched. Check here
To show this loading screen, will I have to do something manually?
You may also want to read this
To add further details after my own research, I found helpful and relevant details in Ember docs.This is all about caching.
If records were already there then promise will be resolved immediately that's why I don't see loading screen for already loaded record, at the same time Ember-Data syncs with backend as well and re-render the template.
Ember Model Docs
Caching
The store will automatically cache records for you. If a record had already been loaded, asking for it a second time will always return the same object instance. This minimizes the number of round-trips to the server, and allows your application to render its UI to the user as fast as possible.
For example, the first time your application asks the store for a person record with an ID of 1, it will fetch that information from your server.
However, the next time your app asks for a person with ID 1, the store will notice that it had already retrieved and cached that information from the server. Instead of sending another request for the same information, it will give your application the same record it had provided it the first time. This feature—always returning the same record object, no matter how many times you look it up—is sometimes called an identity map.
Using an identity map is important because it ensures that changes you make in one part of your UI are propagated to other parts of the UI. It also means that you don't have to manually keep records in sync—you can ask for a record by ID and not have to worry about whether other parts of your application have already asked for and loaded it.
One downside to returning a cached record is you may find the state of the data has changed since it was first loaded into the store's identity map. In order to prevent this stale data from being a problem for long, Ember Data will automatically make a request in the background each time a cached record is returned from the store. When the new data comes in, the record is updated, and if there have been changes to the record since the initial render, the template is re-rendered with the new information.
Related
I'm listing a hasMany relationship, of which a record can be updated, deleted or added.
I want to provide the user with a revert option, which should revert the list to its last saved state.
For deletion, I do item.deleteRecord(), so that I can revert the changes using rollbackAttributes(). Changes are reverted as expected, but it behaves inconsistently while saving (saving the model to which the items belong doesn't update its dirty state on first save, next record disappears from the view though the changes sent to the back-end properly, and so on).
So I decided to use unloadRecord, but once a record is unloaded, I'm unable to revert it without reloading the page.
One way would be to save the old state and use it on revert. Please help me with a cleaner to achieve this.
For an idea of my model, Ember: Model's property changes not detected in computed property
Unloading a record removes it from Ember Data’s in-memory data store.
The only way to get that record back, is by re-requesting it from the server, aka: this.store.findRecord().
You’ll get a fresh copy from the server, but that won’t have any changes the client made before it was unloaded, and may have new changes from other clients.
I am trying to set a default selected item in a semantic-ui-react dropdown. If I select an item from the dropdown, when I reopen the dropdown it opens on the correct item. However, this item is persisted, and when I refresh the page, the correct items are displayed on the dropdown, but it does not open on the correct item.
Please advise.
Matt, it sounds like you are only using the internal component state. Whatever your components initialize with, they will always start that same way. Your entire React application works this way. If you are expecting your data to be persistent, it needs to be stored somewhere. When you refresh you are starting over again. If the state of your application is not being put elsewhere, you lose that state every single time you refresh because the only copy of state is in your client browser.
Basically you currently only have a frontend application that is not storing data anywhere. Depending on your needs, you could do this in a lot of different ways. A REST API. A GraphQL API. One simple way to accomplish this if you are just creating a simple website would be to use a headless CMS. That will give you a database to store your application data. There are a lot of interesting ones out there that you can explore based on your needs.
We are considering moving from Backbone to Ember. There are a few issues through I can't get answers to from the docs.
1) Ember-Data caches it's data. Our application is multi-user so other users need to be able to see new records created by everyone. Is there a way around this? I read on another post that when a query string is passed, ember data does not cache data, is this true? If it is, can I then just always send query string and nothing will be cached?
2) Ember data has a single model in the router that appears to be instantiated at route load time. I can see that your can request data from multiple sources by returning an object with many this.store.find calls. Say I have a select element and when you select an option, another select gets populated with items based on the first select (which requires a call back to the server). How would that work, how can I get model data on demand (not at route load time)?
I'm not sure if it answers your question but you can always call
model.reload()
to refetch data from server so you can work with up to date data.
You may want to consider Faye (http://faye.jcoglan.com/), which would let you have a pub/sub setup that could update your store by listening to topics of interest. This uses WebSocket for the streaming interface. You could then put new objects into the store, remove or update existing objects which the server could publish to the client.
I was told that in order to not make a request all the time, one can use .all() method to load data that is kept in the store. But how does Ember deal with cache? I have a couple of questions.
How do you control cache? When do you use .find() and when .all(). Do you use .find() and then .all()? For how long?
Does .all() have some expiration date so that after some time it can make a new request? Or it uses Local Storage so that I have to clear it manually?
Suppose that I have some data I'd like to refresh only once a week? How should I go about this? Now every time I enter or re-visit the same route a new request is made. How can I avoid this?
So will start by answering question from your comment:
I'd rather to know how can I load data when an app starts (not via routes as I don't have to update it so often). Is it possible
So OK technically this is still via routes, but the best way to load data when an app "starts" is via the Application Route's model hook.
App.ApplicationRoute = Ember.Route.extend({
model: function({
return App.Post.find();
})
})
The router will wait for promise returned by find() to resolve, so you can be sure that response from server has come back before any other routes are entered.
How do you control cache?
Mostly you don't worry about it. You can refresh() an individual record after some timeout if needed.
When do you use .find() and when .all(). Do you use .find() and then .all()? For how long?
Depends what you want to achieve. In our app we use find() in the application route, then either all() or a filter() in other routes.
Does .all() have some expiration date so that after some time it can make a new request?
Nope. It will never make a new request
Or it uses Local Storage so that I have to clear it manually?
It does not use local storage, records are in memory. So for sure an F5 will clear the cache.
Suppose that I have some data I'd like to refresh only once a week? How should I go about this? Now every time I enter or re-visit the same route a new request is made. How can I avoid this?
So OK let's assume you use find() only in the application route, and that user keeps browser open for 1 week and the records have expired. There are many ways to refresh, what's easy/best depends on if they all expire at once or if they time-out one at a time.
Have some timer checks for expired records and calls refresh() as needed.
Have a Ping model that you update on some schedule. When server responds to update it can sideload any changed records.
Or can just refresh the browser once per week (via window.location...)
What you call cache is the content of the store. There are usually 2 ways to update the store to reflect changes made on the backend side:
the change happens with a user interaction/call to the server. If you update mulitple records on the backend side, you can sideload them with the response of that request.
the change happens asynchronously on the backend side (background job). You can use a websocket to push those changes to the client.
Looking for a solution to an issue caused by large data sets forcing Ember to lock up the browser while it tries to process the data.
For pagination, I'm using tchak's handy pagination mixin to paginate approximately 13,000+ objects being loaded from a backend API.
The Ember Data objects contain an ID, one text attribute and several number attributes.
The problem is it takes close to a minute before the browser finishes processing the data, rendering the browser unusable in the meantime. Firefox even goes as far as to issue a warning that a script is using up all browser resources and suggests that script be terminated.
I've written my own pagination mixin that requests objects by range, i.e. items 10-25, and it works generally well except for one serious limitation: sorting. To sort the data, I need to make additional requests to the backend and reload the objects even if some of them have already been loaded.
I would love to be able to load all of the content upfront to simplify the process of sorting without doing additional requests to the backend API. I'm looking for guidance on how to tackle this issue but I'm open to an entirely alternative approach.
If nothing else, is it possible to reduce the resource footprint Ember places on the browser as it tries to load all 13k objects into the ArrayController?
I'm using Ember 1.0.0-pre2 with the latest Ember Data (currently at Revision 10).
On the backend is Rails 3.2.8.
Update I sidestepped the issue by loading data into an ArrayController property other than content. This brought the load times down from over a minute to only a few seconds. I then slice the requested number of items and load those into content. This works well for any number of items, at the cost of not being able to easily sort the data.
I suggest you take a look at Ember Table. The demo shows a table with 500 000 records and works very fast. Digging around the source code might help.
Can't you query a view from your db that handles the sorting? Pass in the sort conditions in the query string ?sortBy=name&sortAsc=true