Hope to know Parent/Child template render order in Meteor - templates

I have really issue on my app development, and hope to get your expert-level help.
<template name="inspection_go">
<div class="transitions-content">
<div class="row toolbar">
<div class="col s1">
{{#if previous_group}}
</i>
{{else}}
</i>
{{/if}}
</div>
<div class="col s4">
{{#if next_group}}
</i>
{{else}}
</i>Complete Inspection
{{/if}}
</div>
</div>
<div class="content">
{{> answer_draw_at_a_location group=current_group building=building inspection_id=inspection._id}}
</div>
</div>
</template>
<template name="answer_draw_at_a_location">
<div class="row" style="margin-top: 20px; height: 100%;">
<div>
{{#each questions_in_group}}
<div style="width: 100%;">{{> question_to_answer question_id}}</div>
{{/each}}
</div>
</div>
</template>
<template name="question_to_answer">
...
</template>
The above code shows parent - child template relation.
And this is the onRendered of parent/sub template.
Template.answer_draw_at_a_location.onRendered(function() {
console.log("parent");
});
Template.question_to_answer.onRendered(function() {
console.log("child");
});
The problem is below.
When I go to inspection_go page firstly, the answer_draw_at_a_location, that is, parent template's onRendered function invoked firstly, after then, the question_to_answer, that is, child template's onRendered function invoked.
And because when I click next_group or previous_group link, it recognize the same template, inspection_go in iron:router, it does not invoke the "answer_draw_at_a_location" onRendered function, so I changed to use #each to invoke it as below.
{{#each current_groups}}
{{> answer_draw_at_a_location group=this building=../building inspection_id=../inspection._id}}
{{/each}}
But now when I click prevoius_group or next_group tag, it execute onRendered function of child template ( question_to_answer ) firstly and after then execute onRendered function of parent template ( answer_draw_at_a_location ).
So I hope to know why it happens, and at least, is there a way to execute parent template onRendered function firstly and after then execute child template onRendered or vice versa.
Please help me.

Related

Ember 2 - Hide / show content component

I have a component app/components/offer-listing.js:
import Ember from 'ember';
export default Ember.Component.extend({
isOfferShowing: false,
actions: {
offerShow() {
if (this.get('isOfferShowing')) {
this.set('isOfferShowing', false);
} else {
this.set('isOfferShowing', true);
}
}
}
});
and his template app/templates/components/offer-listing.hbs:
<div class="offer__container">
<div class="row">
<div class="gr-3">
<div class="offer__avatar" style="background-image: url('{{ offer.avatar }}')"></div>
</div>
<div class="gr-9">
<div class="offer__name" {{action "offerShow"}}>{{ offer.firstname }} {{ offer.lastname }}</div>
<div class="offer__age" {{action "offerShow"}}>{{ offer.age }} ans</div>
{{#if isOfferShowing}}
<div class="offer__description" {{action "offerShow"}}>{{offer.description}}</div>
{{else}}
<div class="offer__description" {{action "offerShow"}}>{{word-limit offer.description 50}}</div>
{{/if}}
{{#if isOfferShowing}}
<div class="+spacer"></div>
<a class="offer__button"><i class="fa fa-envelope"></i> Contacter par email</a>
<a class="offer__button"><i class="fa fa-phone"></i> Voir le numéro de téléphone</a>
{{/if}}
</div>
</div>
</div>
which is rendered in app/templates/index.hbs:
{{#each model as |offerUnit|}}
{{offer-listing offer=offerUnit}}
{{/each}}
The example is working great, however I would like to hide every "more" content when a new one is showing.
A working solution for this is available here : Using Ember component's methods inside template
Basically, either you keep a reference to the selected element in your controller and pass it to each of your offer-listing components. This way they could compare themselves with this reference to known if they need to be displayed or not.
Or you set a flag in each of your offer model depending on whether is needs to be displayed or not.

Getting `this` to work in link-to helper of component

I have a component defined like so:
<div class="col-sm-4 col-md-2">
<div class="thumbnail">
<img src="assets/images/{{image}}">
<div class="caption">
<h5>{{#link-to 'games.game' this}}{{title}}{{/link-to}}</h5>
</div>
</div>
</div>
And I am using it like so:
{{#each model as |game|}}
{{game-details-small title=game.title image=game.image id=game.id}}
{{/each}}
I kind of accidentally got the link-to helper to work by passing in id=game.id as a property. However, if I remove that the link loses the reference to the id. I'm trying to find documentation on how passing in the id makes this reference the id correctly, but I can't find it. Any suggestions, links, or explanation would be helpful.
There is no this inside components, you have to pass the context, in your case you would pass the game:
{{#each model as |game|}}
{{game-details-small model=game}}
{{/each}}
And the template becomes:
<div class="col-sm-4 col-md-2">
<div class="thumbnail">
<img src="assets/images/{{model.image}}">
<div class="caption">
<h5>{{link-to model.title 'games.game' model.id}}</h5>
</div>
</div>
</div>

Ember view with dynamic class names

Considering the following:
Parent template:
{{view App.SomeView id="42" panelClass="default"}}
View template:
<div class="col-md-3 col-sm-6">
<div class="panel panel-{{panelClass}}">
<div class="panel-heading">
<h3 class="panel-title">
{{name}}
</h3>
</div>
<div class="panel-body">
{{description}}
</div>
</div>
</div>
View JS:
App.SomeView = Ember.View.extend({
templateName: 'views/some-view'
});
How can I achieve output HTML where the panel class gets set properly? At the moment it doesn't work because it wants to bind, so it inserts the ember metamorph script tags, instead of just plain text for the panel class.
Also, the template is wrapped in an extra div. How would I modify it so that the ember-view wrapping div is actually the first div in the template (the one with col-md-3 col-sm-6)?
The bind-attr helper exists for that reason. Here's the guide entry.
<div {{bind-attr class=":panel panelClass"}}></div>
Also, not sure if you can use a prefix on panelClass in the template. If might be easier just to use a computed property to add the panel- beforehand.
I'm sorry, I didn't see your second question about the extra div. The guide explains here how to extend the element.
App.SomeView = Ember.View.extend({
classNames: ['col-md-3', 'col-sm-6']
});

How to set itemController for instance variable in ember.js indexController?

I have a Ember.js page that displays a table of items and shows details of one of the items when it is selected. The controller looks like this:
CV.IndexController = Ember.ArrayController.extend({
itemController: "CurrVitae",
selectedCurrVitae: false,
actions: {
selectCurrVitae: function(currVitae) {
this.set('selectedCurrVitae', currVitae)
}
}
});
And the index controller is used in a template like this:
<div class="container">
<div class="curr-vitae-list">
{{#each curr_vitae in controller}}
<div class="curr-vitae-item row">
<div class="col-sm-2" {{action selectCurrVitae curr_vitae}}>
{{curr_vitae.name}}
</div>
<div class="col-sm-2">
<!-- NOTE: This method is defined on the item
controller (not the model) so the itemController is
available at this point. -->
{{curr_vitae.createdAtDisplay}}
</div>
<div class="col-sm-7">
<div class="embedded-cell">
{{curr_vitae.summary}}
</div>
<div class="embedded-cell">
{{curr_vitae.objective}}
</div>
</div>
</div>
{{/each}}
</div>
<div class="curr-vitae-view">
<h2>Details</h2>
<!-- EDIT: I have tried setting this
as {{#if selectedCurrVitae itemController="currVitae" }}
to match the way the #each handles item controllers but that did
not seem to work -->
{{#if selectedCurrVitae }}
<!-- NOTE: Down here, however, the item controller is not available
so I can't use methods defined on the item controller for the
currently selected instance. -->
{{ partial "cv_index_details" }}
{{/if}}
</div>
</div>
Question: The problem I'm running in to is that the itemController I've set in the index controller is not available when rendering the selectedCurrVitae in the cv_index_details.
More details:
Specifically, in the partial I want to reuse a editor component (taken from Noel Rappin's Ember.js book). So if the cv_index_details partial looks like this:
<h3 class="selected_cv">{{selectedCurrVitae.name}}</h3>
<div class="row selected_cv_summary">
<h4>Summary</h4>
{{block-editor emberObject=selectedCurrVitae propName="summary" action="itemChanged"}}
</div>
<div class="row selected_cv_experiences">
<h4>Experiences</h4>
{{#each experience in selectedCurrVitae.experiences itemController="experience"}}
{{ partial "experience_detail" }}
{{/each}}
</div>
So in this template, the itemChanged action is not found for the selectedCurrVitae instance. However, I use the same block-editor component for the experience instance and that works correctly; the itemChanged action defined on the ExperienceController is found.
selectedCurrVitae is outside of the itemController, the itemController is only applied inside the each (on each item, hence the name).
Probably the easiest way to accomplish this will be to reuse the item controller and use render.
Template
{{#if selectedCurrVitae }}
{{ render "cv_index_details" }}
{{/if}}
Controller
CV.CvIndexDetailsController = CV.CurrVitaeController.extend();
Or
Template
{{#if selectedCurrVitae }}
{{ render "currVitae" }}
{{/if}}
View
CV.CurrVitaeView = Ember.View.extend({
templateName: 'cv_index_details'
});

Ember.js best practices for adding subnav

I was curious as to what the best way is to implement sub navigation in Ember. In application.hbs I have the main nav with 'about', 'programs', etc. When 'about' is clicked I would like another list of pages to display on the row directly below the main nav. I'm already using {{outlet}} inside of application.hbs so I can't put another where I want the subnav to display.
Here's what I have:
<div class="row left-nav">
{{#linkTo "index"}}<img class="ew_logo" src="assets/ew.png">{{/linkTo}}
</div>
<div class="row nav">
<div class="large-12 colummns">
<ul class="inline-list top-nav">
<li><h6>ABOUT</h6></li>
<li><h6>//</h6></li>
<li><h6>CONDITIONS</h6></li>
<li><h6>//</h6></li>
<li><h6>PROGRAMS</h6><li>
<li><h6>//</h6></li>
<li><h6>TESTIMONIALS</h6></li>
</ul>
</div>
</div>
<div class="row subnav">
<div class="large-12 colummns">
// Would like SUBNAV to display here
</div>
</div>
{{outlet}}
You could use a named outlet and hook into the renderTemplate function of your route to render it into the right place, see here for a simple demo. (sorry, but the styles are obviously screwed)
Example if your named outlet is inside your index template then you could:
Index Template
...
<div class="row subnav">
<div class="large-12 colummns">
{{outlet 'subnav'}}
</div>
</div>
...
Subnav template
<script type="text/x-handlebars" id="subnav">
<h2>Hello I'm Subnav!</h2>
</script>
Index Route
App.IndexRoute = Ember.Route.extend({
renderTemplate: function() {
this.render(); // this renders the index template per se
// and this additional call renders the subnav template into the named outlet
this.render('subnav', { //the name of your template
outlet: 'subnav', //the name of the named outlet
into: 'index' //the name of the template where the named outlet should be rendered into
});
}
});
Note, you can have as many named outlet's as you want as long you render them like mentioned above, no matter what route you are in.
Hope it helps.