It appears the model hook is not working as documented for RC1. The model hook is not being called when a linkTo is used instead of visiting the item directly by editing the url in the browser.
Given this example app: http://jsfiddle.net/wmarbut/QqDjY/
When visited directly at '/#/edit-item/3', the model hook is called, however when a linkTo call is used to direct the user to the same page, the model hook is not called.
Given the documentation here http://emberjs.com/guides/routing/specifying-a-routes-model/, I can't find anything to explain this. Is this a bug or am I doing it wrong?
Edit
I'm not using Ember Data nor do I plan to.
It appears the model hook is not working as documented for RC1. The model hook is not being called when a linkTo is used instead of visiting the item directly by editing the url in the browser.
This is the exact way it's supposed to work. This is because the model is given via linkTo. When you write {{linkTo posts post}} the model is the 3rd argument. There is no need to call the model hook. The model hook is only executed when entering a state via the URL because it must look up a model.
In your fiddle you have {{#linkTo editItem item.id}}{{item.name}}{{/linkTo}}. You do no need to do that. You should have {{#linkTo editItem item}}{{item.name}}{{/linkTo}}. This will not solve the "problem" however. It will make the lookup automatic.
Related
In React's documentation they recommend generally abstaining from the use of this.forceUpdate, instead recommending to use this.setState whenever possible.
In my application I have a component that contains a slide-out pane. It has nested elements and clicking each item updates the URL in a different way. For example, I could navigate to the following URLs by clicking around in it:
site.com/posts/create
site.com/posts/read
site.com/posts/4895734
site.com/posts/5465462
site.com/messages/43455
site.com/messages/create
Clicking each of these items should update the component's view and display it differently based on the URL. However, just calling window.history.pushState to update the URL does not cause React to update (you need to call setState or forceUpdate for that).
As a result, I am unsure of how to proceed. I rather not duplicate the "source of truth" and mirror the URL in React's state variables, because then there is conflict over whether or not the URL should be used to determine the state versus the component's state variables. It seems better to have the URL be the single source of truth.
However, if this is the case, then every time I change the URL I would have to do this.forceUpdate or some no-op call like this.setState({ asdf: 5 }). This would certainly work, but React's documentation specifically warns about calling forceUpdate all over the place in the application.
Is there a better way?
I'm not sure what routing configuration you have, but are you using the history package?
https://reactrouter.com/core/api/history
https://www.npmjs.com/package/history
Example:
https://codesandbox.io/s/vigilant-dhawan-qf6ke?file=/src/App.js
That should mount/rerender on url changes, as well as give the ability to pass state through the router.
Edit:
Simplified version
https://codesandbox.io/s/trusting-cookies-pyhq6?file=/src/Router.js
My routes look roughly like this:
```
/
/sites
/:site_id
/settings
/user-defined-params
/:param_id
```
Now in /user-defined-params I want to display table-list of parameters assigned to that given site. The models are not related, I mean site doesn't have collection of params as a relation, so I can't simply fetch them via this relation.
Should model() hook for my router return list of these params? By default the model seems to be site loaded from parent route (:site_id). What if loading takes some time and I'd like to actually display this table (so do actual transition) but then show kind of loading indicator waiting for table to fill in with the data.
When I try to load this in model() hook, transition blocks. When I try to load it in afterModel() hook, I don't have a way to assign it and make it available for template (other than force-assigning params property to site model, which seems to be wrong).
All the examples I've found over the Internet seem to be lacking this scenario, which I feel is one of the basic ones, so any hints on that? How should I load it (ideally without blocking transition)?
The defaults in Ember's current router (as you have found) are to block UI loading completely until the promised returned in model hooks have resolved. However, there's interest in adjusting that so we can easily build non-blocking UI patterns with the built-in router.
Right now, the community consensus here is to use ember-concurrency and it's derived state (specifically the .isRunning aspect of tasks) to toggle between a loading state and a screen with the data rendered. It isn't a coincidence that ember-concurrency was built by the guy behind the first router and the current router re-think that is in-process.
One example of an approach to this is outlined here:
https://emberway.io/skeleton-screen-loading-in-ember-js-2f7ac2384d63
I personally prefer to use my route to do the initial task loading and the consume the data in the template. But in a more complex UI I also will go with container components as outlined in that article.
When answering other question I made incorrect statement writing that ApplicationRoute.beforeModel() hook is ran after every transition. When made aware of this fact I confirmed that the hook is ran only once using barebone Ember app.
Unfortunately, there was nothing I could found in documentation that would explain this behaviour. First paragraph of beforeModel documentation states:
This hook is the first of the route entry validation hooks called when an attempt is made to transition into a route or one of its children.
As for ApplicationRoute - there is not a lot about it, in action bubbling part of the guide we can find information that action bubbles from controller through route to its parent and it lists ApplicationRoute as a top parent of routes:
If neither the template's controller nor the currently active route implements a handler, the action will continue to bubble to any parent routes. Ultimately, if an ApplicationRoute is defined, it will have an opportunity to handle the action.
Logically, this should mean, that every transition should run ApplicationRoute hook which is in contrary to what actually happens.
So the question is:
Why ApplicationRoute doesn't answer to transition events and what are the other differences from defined Routes?
It seems like your main questions is: why doesn't the application route run with every transition? The long answer is a bit complicated, but the short answer is: because it doesn't have to.
For the long answer, let's make an example route hierarchy.
application
index
photos
view
new
A pretty simple set of routes. Now let's suppose that you wanted to visit the photos.view route. Ember would follow these steps:
Run the application route hooks. (Including beforeModel, model, and afterModel).
Run the photos route hooks. (Including beforeModel, model, and afterModel).
Run the view route hooks. (Including beforeModel, model, and afterModel).
Ember has to initialize the route for every parent route of the route you want to visit. That makes sense. But let's say you transitioned from photos.view to photos.new. Ember isn't going to re-run the application and photos route setup hooks. It doesn't need to. Those models have already been resolved and nothing has invalidated them. Ember is only going to run the photos.new setup hooks. If you transitioned to the index route, it would only run setup hooks for that route, not the application route.
Short story long, Ember isn't go to re-run setup hooks and model fetching logic if it doesn't have to. Unless you invalidate some cached data, or force a reload, Ember is only going to run your application route hooks once.
If you want logic that runs before every transition, something that I've done before is to create a base route that all of my routes extend from, then override the activate hook.
I want to run some view code when the model that the view is bound to changes.
My view has an observer on the controller model, like so:
App.SomeView = Em.View.extend
modelDidChange: (()->
# do stuff
).observes('controller.model')
When the model changes, modelDidChange is called twice.
Why is that?
Is there a better/different way to achieve what I'm trying to do here?
Using Ember 1.3.0.
Are you sure that your view needs to know when the model changes? The view's template gets its properties from the controller, and should update automatically when they change. You certainly want to avoid any observers if you can.
But I don't know much about your use case, so assuming that it's necessary, I would try a debouncer. It's likely that the model isn't changed twice, the event is just fired twice. Ember has a LOT of action that happens in between user hooks, so the model is probably just set to the same value twice. Use a debouncer to have your method called just once.
Ember.beginPropertyChanges();
# model updates
Ember.endPropertyChanges();
The first time it fires because you made a change in your browser and that change gets sent to the Ember data store which triggers the observer callback. The store then makes an update request to the backend which responds with an updated model, when the store receives this updated model it triggers the observer callback once again.
I'm pretty new to this world so I need some clarifications on it. Maybe I could be wrong on the subject. So, feel free to correct me.
I'm studying how Marionette and Backbone work together. Oh yeah. Marionette gives us extension to Backbone. Really nice stuff.
The thing that is not obvious to me is when to use the routing mechanism provided by Backbone and when to use publisher/subscriber pattern by Marionette.
Is there any rule of thumb?
Here, Where to use event aggregator in backbone marionette?, a similar discussion but there is no advice on how using that or the other.
My take on the route management is explained in the free preview to my book on Marionette (http://samples.leanpub.com/marionette-gentle-introduction-sample.pdf)
Basically, my opinion (others don't necessarily share it) is that Backbone's routing should be used to configure the application state when the user "enters" the application via a URL. In other words, it will parse parameters, and call proper controller actions.
But once that initial state is setup, routing code should no longer be triggered, even as the user navigates through the application.
Here's an example:
The user enters arrives on the "contacts/2/edit". Backbone routing code will extract the 2 argument and call the edit controller action with that id parameter (which fetches that contact, displays the proper views, etc.). In other words, the initial application state is being configured.
The user clicks on the "show all contacts" link leading to the "contacts" URL. Here, I believe this modification should be handled through Marionette events (i.e. indicating the user wants to see all contacts). After all, we know what the user wants to do, and which URL fragment should be displayed. In other words, there is no reason for the routing code to get involved.
Note that this is my opinion, and other developers simply pass trigger: true when the user clicks a link. But as I explain in the book extract linked above, this tends to lead developers to create "stateless applications in javascript" (e.g. passing lots of parameters in the URL, even though they should be stored in the application's state). Ater all there is a reason that by default, Backbone's navigate method has trigger: false.
Derick Bailey (Marionette's creator) also discussed the issue here: http://lostechies.com/derickbailey/2011/08/03/stop-using-backbone-as-if-it-were-a-stateless-web-server/
Event aggregator is more useful for notifying things. (think small bits of feedback)
Message from server (updated record)
Let other models know things have changed
Lock everything down while saving until saved
Single Moment in time things
Router is for things where you want the state to be save-able (think separate page in a MPA)
Model Edit Page
Model View Page
Something that will stay until another event or activity changes it
If you are not sure if something is an event or a page, then think about it and ask that separate question.