Iron Router dynamic routes don't re-render - javascript

I have a route that looks like this:
#.route 'dailyTotal',
path: '/report/:year/:month/:day'
template: 'dailyTotal'
layoutTemplate: 'report'
data: ()-> this.params
And in my controller something like this:
Template.dailyTotal.bevTable = ->
params = this
# a whole bunch more...
In the controller, I use those params to do some rather complicated stuff that isnt' relevant to my question because this doesn't re-render (or execute?) when you navigate from one dynamic route to another.
For example, if I navigate from "/report/2014/05/21" to "/report/2014/05/22" nothing happens. That route only executes if you come from a completely different route (say, "/report/totals" for example).
When I put a break point in the controller it never gets this, but I see the params change within the data function. My gut tells me I need to somehow force the controller action to run, but it isn't obvious from either the IronRouter or Meteor docs. Any suggestions?

I tried to reproduce your issue by creating simple meteor app with route you published above, but no luck, IronRouter properly handles this case.
Please compare your code with :
https://github.com/parhelium/meteo-so-ironrouter-dynamic-routes
IronRouter properly detects change of params in the same route, so going first to /report/2014/05/21 and then to /report/2014/05/21 re-renders template properly.
App structure was generated using em tool, it generated a lot of dirs and files, but only few are important in this situation:
both/router/routes.js
client/controllers/report.js
client/views/report/*
Update
When you pass this.params through data field in controller then usage in template for your route is:
{{year}}/{{month}}/{{day}}

Related

EmberJS: How to find which controller is used to drive .hbs view?

I have inherited a codebase and trying to make sense of what is what. In emberjs application how do I know which controller (js) corresponds to a view (hbs) on a particular page. Is there a setting? Is there a convention?
The convention is that their names (or more accurately their paths) should be the same.
As in, controllers/page.js should have a templates/page.hbs and a routes/page.js
You can see this convention if you create a new Ember project using ember new or ember twiddle.
You can also specify the template name within a route using the templateName property.
// routes/page.js
import Route from '#ember/routing/route';
export default Route.extend({
templateName: 'something/different'
});
Ember also allows us to use the renderTemplate hook within our routes and pick a different template and/or a different controller.
// routes/page.js
export default Route.extend({
renderTemplate(controller, model) {
// Render the `something/else` template
// and use the and `other/thing` controller
this.render('something/else', {
controller: this.controllerFor('other/thing')
});
}
});
Read more in "Ember JS Guides: Rendering a template"
Ember also used to allow embedding templates within other templates using the partial helper.
It would matter a lot which Ember version you are using because that would restrict your concerns to a certain API behavior, since Ember did change a lot through the years.
For the most part it's pretty simple. Ember follows convention over configuration so let's learn the convention. The algorithm is as follows.
Look at the current url that you are on. In this case, we are on /foo
Open up the router.js file and find the route that matches this url pattern. If you don't specify paths then the url will just be the name of the route, but you could also be dealing with nested routes. Let's say we found route named foo.js which would be under appName/routes/foo.js.
Open the route file. Routes jobs are to fetch data in the model hooks, and then to set the variables on the corresponding controller instance via the setupController(controller, model) hook. When not specified, this method just sets the entire model object on the controller. Now we should have a decent idea of what variables have been dynamically set on the controller.
Open the controller under appName/controllers/foo.js. The best way to think about controllers is they are the single source of state for the corresponding template (appName/templates/foo.hbs). Their values are set via hooks on the route, as well as through the init method, computed properties, observers, etc. When you reference any {{variable}} in a handlebars template, the controller that matches this portion of the page's context is the source of state that resolves this variable. If the controller isn't defined, then Ember autogenerates one for you. Worth noting that controllers are singletons and their state persists between route changes.
Open the template.hbs file to see your markup. You might have components (custom html-looking tags that take attrs) which store their javascript under appName/components/component-name.js and their templates in appName/templates/components/component-name.hbs or have no template if the javascript file can just specify a tagName and that's it.
One other quick thing: routes are invoked in a parent/child hierarchy and correspond to urls via the route. The top level route is the application route. If you look in it's template, you will find an {{outlet}} Ember will then find whatever child route comes next and render its template into this outlet. by default /, the index route's template is rendered. But if the url was /foo then foo.hbs will be rendered into the application's outlet. Foo.hbs can have an outlet, and thats when we start getting into nested routes. That's about as quick/high level overview as I can give, ask any questions if you want specifics (I love Ember)

Is it possible to reload the router in a running ember.js app in order to update the path strings of routes?

I'm implementing multi-language support in my app, and I guess this is the last thing that I would need in order to be able to change between languages without reloading the whole app/page. (I already have a solution with full page reload.)
For a simple example let's say this is how my router looks:
Router.map(function() {
this.route('search', { path: t('search') });
this.route('item', { path: `${t('item')}/:id`);
});
The t function would be getting the correct translation for the given strings in the currently active language.
The structure of the route hierarchy won't change, the only things that need to be updated are the path strings. Application state should be kept, of course.
I'm wondering whether this is possible to do.
I am not %100 sure about the correctness of what I wrote but Router.map is executed and resources with the definitions given within this method is transformed to a DSL instance and that is then passed to the actual router maintained by Ember.Router itself. In order to achieve what you want I believe what we need is dynamic modification to the router even if it is just the paths you need yo modify not the whole route structure.
If you look at the following github issue, Ember.js no more supports dynamically adding routes (hence no dynamic modification to the existing ones I believe). With all that said, I believe what you want is not possible without reloading the whole app (hence losing the application state).

Ember.js data from a route does not show in template

as you can see, hbs has a placeholder for {{abcd}} and route returns the value for abcd but my page does not show that data. When i do a view source, i can see that js function is carried into the page! Am I missing something? do I need to write something in controller folder before route and model/template can talk to each other?
Templates don't know anything about route properties. {{abcd}} would refer to a controller property. In order to access it you will have to go through the controller's model property {{model.abcd}}.
I would recommend you give the guides a thorough look.

Ember JS renders default template after adding new route

I'm trying to make some proof of concepts, and learning the ember js framework concepts. I came across an issue, that is bugging me for hours... here's the thing:
I created a simple ember-cli app using the windows command prompt. Everything works fine, the default route get's hit and the application.hbs is rendered.
After that I added a blogposts.hbs to the templates, that has just static html:
<h1>Blog posts</h1>
<div>These are the blogposts:</div>
Also added a route to the /router.js
Router.map(function() {
this.route('blogposts',{path: '/blogposts'});
});
// -or-
Router.map(function() {
this.route('blogposts');
});
Tried both of the above. And added a linkto to the application.hbs that should link to the blogposts route.
<h2 id="title">Welcome to Ember</h2>
{{#link-to 'blogposts'}}Blogpost linkto{{/link-to}}
THE PROBLEM: this route seems like never gets hit. I tried to navigate to localhost:4200/blogposts, tried the link that's generated, I also tried the hash: #/blogposts, but none of these render me the blogposts template. If I understand it correctly ember should generate a default controller for the blogposts if I don't specify one, and also a model shouldn't be required to render that template. I know this has to be some minor thing that I'm missing, but I can't seem to understand where am I wrong.
Every helps is much appreciated!
Thanks!
PS. I almost forgot, I am using the following:
Ember : 1.13.11
Ember Data : 1.13.15
jQuery : 1.11.3
OK, just 5 minutes after I posted the question I got the answer! I was missing the {{outlet}} from the application.hbs!
It was not clear for me that the application.hbs is like a layout of some sort, and it will allways be rendered. I thought that based on the routes the application.hbs will be replaced by the blogposts, but it's not like that.
With the default routes in place the application template will be rendered first and the additional templates will be rendered to placeholder (the {{outlet}}).

Ember strange behavior when two instances of same template used in multiple places in application

Please take a look at this JSBin1. I am using the same template for both the render in the index template and manually rendered in the renderTemplate function of the ColorsRoute. Clicking the More Colors link does not render the list of colors I return in the ColorsRoute model hook. Now, if you change the render 'colors-list model to render colors-list2 model, as I have done here, everything works as I would expect it to. The only difference between the two is that in JSBin1, I am only using the colors-list template, but in the second working example, I have one template for the render and an identical, differently named template for the ColorsRoute.
The code example, while trivial in the JSBin, is an exact extraction of something I am doing in a much larger application. This application has a bunch of widgets, which I represent by multiple named outlets in the same templates. I manually render into these outlets, as I do in the JSBin in the ColorsRoute renderTemplate hook. I do the manually rendering so that when certain events happen, I have actions defined on the route that will allow me to dynamically replace the contents of the outlet after making an ajax call to a REST API.
What is the explanation for this kind of behavior?
It's more related to the controller that's being created, not the template. And technically I'd say it shouldn't work on either, but it appears there's some route where if you don't define a controller, and that type of controller hasn't been created, create it, and use the current controller/model as the model backing it.
Really you should be providing a controller when using render if you're expecting it to have that controller as the backing controller.
renderTemplate: function(controller, model){
this.render();
this.render('color-list', {
outlet: "named",
into: 'colors',
controller: controller
});
}
http://emberjs.jsbin.com/cevagocekofu/3/edit

Categories