Get Object attribute with array Notation inside ember template - javascript

Just trying something but not sure how to do it.
Scenario:- I'm trying to render a page which have a configuration data and view data, so basically My template loop on the configuration data to render page and fetch value from view data to display.
so my model have something like
model:{'confData':[{'displayName':'value1','fieldName':'Field1'},
{repeat similar object}
],
'viewData':{'Field1':'value1','Field2':'value2',....}
}
Now in template I'm trying to render like:
{{#each confData}}
this.displayName {{input type='text' value=viewData[this.fieldName] }}
{{/each}}
but it does not accept it. Any suggestion on how I can deal with this sort of problem.
PS: the confdata and view data in actual application will be api call which i can't change.
I saw somthing like http://jsfiddle.net/GRaa5/4/ but when I tried changing as http://jsfiddle.net/weyzay5v/ it failed.
Thanks.

There is no way to do what you want purely with Handlebars. Remember that Handlebars templates are logic-less and for presentation only. My suggestion would be to make a computed property in your controller:
data: function() {
var confData = this.get('confData');
var viewData = this.get('viewData');
return confData.map(function(data) {
return {
displayName: data.displayName,
value: viewData[data.filedName]
};
});
}.property('confData.[]', 'viewData')
Then in your template:
{{#each data}}
{{displayName}} {{input type='text' value=value}}
{{/each}}

Related

Iron router with Meteor display data to template

I am using iron router with Meteor (latest versions). I have a template:
<template name="home">
{{#each products}}
<p>{{name}}</p>
{{/each}}
JJJJJJJJJJJJ
</template>
and in lib/router.js:
Router.configure({
layoutTemplate:'layout'
});
Router.map(function () {
this.route('home', {
path:'/',
template:'home',
data : function () {
return Products.find();
}
});
});
When I run the page, I see empty page with this JJJJJJJJJJJJ, added for test to see is it template loads.
In the Products collection are 2 items with name. I can read (select), add, remove items for this collection via WEB browser console, but the collection is not rendered in the template.
What can be the error ?
The data function of Iron Router sets the data context for the template. In your case, you are setting the data context to be a cursor but attempting to access the cursor with products, which does not exist as a helper, either registered globally or on the template itself.
There's a few ways you can fix this, but I would suggest letting the router simply determine which template to render and let the template fetch it's own data.
Adjusted router:
Router.map(function () {
this.route('home', {
path: '/',
template: 'home'
}
);
Template helper:
Template.home.helpers({
products() {
return Products.find();
}
});
Alternatively, you can use the this keyword within the template to access the current data context:
<template name="home">
{{#each this}}
<p>{{name}}</p>
{{/each}}
JJJJJJJJJJJJ
</template>
However, it is not easy to discern what is being put into this unless you can follow the flow of the data through the route to the template. This also couples this template very tightly with this route, as the route itself is determining the context of your template.
The solution is in lib/router.js, need to set attribute data like this :
data : function () {
templateData = {
products: Products.find()
};
return templateData;
}
, NOT like before - return Products.find(); .

Ember: How to access another model data in a dynamic segment template

In a dynamic segment template, how do you display data from a model using the route ?
so for example I have those three routes with phone_id as dynamic segment
Router.map(function() {
this.route('phones');
this.route('phone', {path: 'phones/:phone_id'});
this.route('numbers');
});
in phones/:phone_id template, I am trying to show all the numbers model. so in phone.js route, I tried to return the number model and output it but it showed nothing.
import Ember from 'ember';
export default Ember.Route.extend({
numbers(){
return this.get("store").findAll('number')
}
});
I tried it also with the params.phone_id as argument but it did not work. (no error was shown also).
the template phone.hbs looks like
<h5> Device Id: {{model.device_id}}</h5>
{{#each numbers as |number|}}
{{number.digits}}
{{/each}}
funny thing is model.device_id returns the correct one even though I did not even set it to return that in phone.js route. But the each loop for numbers which I did implement something for does not return anything.
Is there a workaround to return number model data in phone.hbs dynamic segment template ?
EDIT:
the way I am reaching my dynamic segment is through a link to:
{{#each phones as |phone|}}
<li>{{#link-to 'phone' phone}} {{phone.id}}{{/link-to}}</li>
{{/each}}
Only object from returned from model hook of route is set as model of controller.
if you want to use numbers as it is in template then write it as a computed property in controller.
numbers:Ember.computed(function(){
return this.store.findAll('number');
});
or you can set these properties in model itself
so model hook of your route will look like this
model:function(params){
return Ember.RSVP.hash({
phone: this.store.findRecord('phone',params.phone_id),
numbers: this.store.findAll('number')
});
}
after this you will get two properties in your model
Now your template will look like this
<h5> Device Id: {{model.phone.device_id}}</h5>
{{#each model.numbers as |number|}}
{{number.digits}}
{{/each}}

accessing dynamic input values in ember #each block in ember

I'm having issues accessing input values within my component. I'm trying to dynamically create value bindings in my templates and accessing in the conponent.js file using this.controller.get("pst"+id) however the result is underfined. Using Ember 2.2
{{#each post in |pst idx|}}
{{input value=(concat 'pst' idx)}}
{{/each}}
Well, it works as expected, but why would you want to do this?
Please explain what you want to archive and then we can help better.
And to be clear, a value generated with the get helper is immutable.
Why not do something like {{input value=pst}}?
If this is not an option probably you should build your array in JS and use that then in handlebars!
Define a computed property that wraps your 'post' variable in your component.js file. Iterate over that wrapper. I think this is a powerful way of generating dynamic values.
Your template:
{{#each postWrappers as postWrapper}}
{{input value=postWrapper.value}}
{{/each}}
Your component.js:
postWrappers : Ember.computed('post', function() {
//your concat code
});

How do you render multiple templates with one route controller using iron-router?

URL to current version of my project
Here is the code for my project
Background:
I am making a blog using meteor and iron-router. I want to use a single controller for several different "category pages," which filter a list a blog articles in the yield region.
The Problem:
The article list does not get rerendered when the URL changes. I.e. the article list is not reactive. Interestingly, if I navigate back to the home page, the correct article list shows up.
The Question:
How do I make that article list change when I change between different routes on the category route controller?
Some example code:
Please note that the code for this whole project is available here.
Here is my Route Controller:
CategoryController = RouteController.extend({
action: function(){
this.render();
},
template: 'category',
data: function(){
return {category: this.params.category};
}
});
CategoryController.helpers({
articles: function(){
return Articles.find({category: this.params.category});
}
});
And here is the template it is rendering:
<template name='category'>
<div class="container">
<h2>{{category}}:</h2>
<ul>
{{#each articles}}
<li>
{{#linkTo route="article.show"}}
{{title}}
{{/linkTo}}
</li>
{{/each}}
</ul>
</div>
</template>
Resources/Updates:
Read this article on Meteor Reactivity and the Deps Package. Very interesting, but after trying some Deps.autoruns in different places, I don't think that this is the answer.
Currently trying to make different "category" routes inherit from the controller.
The article list does not change because the Template helper is not using a reactive data source. You may use the RouteController.getParams method to establish a reactive dependency on route parameters as shown below.
CategoryController.helpers({
articles: function(){
var controller = this;
var params = controller.getParams();
return Articles.find({category: params.category});
}
});
From Iron Router documentation:
Note: If you want to rerun a function when the hash changes you can do
this:
// get a handle for the controller.
// in a template helper this would be
// var controller = Iron.controller();
var controller = this;
// reactive getParams method which will invalidate the comp if any part of the params change
// including the hash.
var params = controller.getParams();
By default the router will follow normal browser behavior. If you
click a link with a hash frag it will scroll to an element with that
id. If you want to use controller.getParams() you can put that in
either your own autorun if you want to do something procedural, or in
a helper.

Emberjs: How to render a view with the view name in variable?

i would like to add some cards to a board, all cards are very different. so i want to create different view for each card that can bind different events and template. I set a 'type' property in the card model which to distinguish the cards.
the board template look like below:
{{#each card in cards}}
{{render card.type card class="card"}}
{{/each}}
However, the first argument for the render help can not be a variable, it can only be the card view name string.
anyone know how to achieve this?
As you already mentioned the built-in render helper only accepts a string to lookup the template to render, therefore one possible solution would be to write your own custom render helper, which then after getting the correct name with card.get('type') delegates the rendering to the built-in render helper. This could look something like this:
Ember.Handlebars.registerBoundHelper('renderCard', function(context, card, options) {
return Ember.Handlebars.helpers.render.call(context, card.get('type'), 'card', options);
});
After that, you could use it like this in your template:
{{#each card in cards}}
{{renderCard this card}}
{{/each}}
Edit
I've also added a basic jsbin that shows it working.
Edit 2
Edited the jsbin again, using object data to be rendered into the template, see here.
Edit 3
Lamentably the DS.FixtureAdapter does not support embedded records which is what you need to make it work. But you could configure you orignal DS.RESTAdapter like this:
App.Adapter = DS.RESTAdapter.extend();
App.Adapter.map('App.Dashboard',
cards: {embedded: 'always'}
);
App.Store = DS.Store.extend({
adapter: App.Adapter
});
This way the card records are always loaded with the parent record. I guess doing this change would make the call to card.get('type') in you handlebar helper return the value rather then undefined.
Hope it helps.
For Ember 1.9 solution above doesn't work. Use another way to register helper:
Ember.Handlebars.registerHelper 'renderDynamic', (context, model, options)->
contextString = options.hash.contextString
model = options.data.view.getStream(model).value()
return Ember.Handlebars.helpers.render(model.get('type'), contextString, options)
And in the template:
= hb 'renderDynamic "this" currentModel contextString="curremtModel"
or in handlebars:
{{renderDynamic "this" currentModel contextString="curremtModel"}}

Categories