Handlebars: Accessing JSON Property of Parent using child property - json

I was wondering if there is a way to simplify this handlebars template to not use a helper.
Data:
{
games:[game: {teamID:1}]
teams:{1:{name:'Team Name'}}
}
Template (note that is is within a {{#each games}}:
{{#teamFetch ../this teamID 'name'}}{{/teamFetch}}
Helper:
Handlebars.registerHelper('teamFetch', function(season, teamid, property){
return season.teams[teamid][property];
});
I'm new to handlebars but this was the only way I could figure out how to access a specific team in the season based on the id within a game, and get a property of that team. Is there a simpler way that doesn't require a helper function?

There isn't a way to get around not using a helper. This is because Handlebars doesn't allow you to pass a variable in their segment-literal notation for specifying variable paths. In the Handlebars documentation regarding Expressions:
To reference a property that is not a valid identifier, you can use segment-literal notation: {{#each articles.[10].comments}} {{/each}}
So...ideally, we want to be able to do something like this:
{{#each games}}
{{../teams.[teamID].name}}
{{/each}}
But as of right now, there is no way to pass in the value of teamID into ../teams.[ ].name.
It is only capable of doing this:
{{#each games}}
{{../teams.[0].name}}
{{/each}}
It can only interpret values, eg. 0, and unable to resolve variables eg. teamID

Related

panini each helper - how to pass property instead of path?

I embed a component in another component. From the parent I want to pass a property that will contain the name of the file from which this list will have to receive data. Can Panini do this?
something like this child must have:
<ul class="cards-grid__list cards-grid__list--2">
{{#each cards-grid-2}}
{{> img-card }}
{{/each}}
</ul>
Is it possible somehow instead of the file name "cards-grid-2" that the each-helper requires, to give a property that will contain the name of this file?
parent:
<div class="cards-wrap">
{{> cards-grid
mod="cards-grid__list--2"
grid="cards-grid-2"
}}
</div>
something like this i need in child:
<ul class="cards-grid__list {{mod}}">
{{#each !{{grid}}! }}
{{> img-card }}
{{/each}}
</ul>
{{mod}} - has no problem.
!{{grid}}! - is impossible, certainly. But here I want to somehow pass a property instead of a file name in order to use this component in different places through the parent, but with different data sets.
!{{grid}} was (grid), [grid], "grid", \grid\ and something like, but anything not working. And I didn't find any information if value can be passed at all.

How can I use index while iterating over JSONArray in handlebar?

I am trying to show the details of the adultJsonArr in different and I want to get it saved on action without going into writing lengthy code.
I'm not getting idea of how to use the index while iterating, I tried as mentioned in line no 5 but didn't work( #index also couldn't do job for me).
Any suggestion on how to save the changes made to the input in the adultJsonArr
1.<form>
2. {{#each adultJsonArr as |adultTravellerDetails index|}}
3. <div id="adult_form{{index}}">
4. Adult{{index}}:
5. <input type="text" value="{{adultJsonArr.[index].traveller_name}}" required>
6. <input type="dob" value="{{adultTravellerDetails.traveller_dob}}">
7. <input type="text" value="{{adultTravellerDetails.traveller_gender}}" required>
8. </div>
9. {{/each}}
10. <div {{action "confirmTravellerUpdate" adultJsonArr }}>
11. {{mdl-button text='submit'}}
12. </div>
13.</form>
You can replace {{adultJsonArr.[index].traveller_name}} with {{adultTravellerDetails.traveller_name}}.
If you would like to access a certain element from a array you should not do this in your template. The ember devs have made it hard to do so because it would likely put to much logic into the template. Use instead a computed property or a helper to retrieve your element from the collection.
E.g. you can create a helper function that receives a collection and a index and returns the desired item.
import { helper } from '#ember/component/helper';
export function colItem(params) {
return params[0][params[1]];
}
export default helper(colItem);
And in your template:
{{helper-name collection 5}}
But remember that for this you would need an array to work. If you would like to access an item from another collection you would have to handle this accordingly.
The index should probably only be used for display purposes. There's no need to look up things within the current index of adultJsonArr because you already have access to adultTravellerDetails.
Having said that, if you really have some use-case where you need to look up the value of the array at the current index, (or maybe you have some other sorted array with meta-data that you want to look up by index?) you can do something like this:
{{get adultJsonArr (concat index ".traveller_name")}}
We are building a path with concat for get to look up on adultJsonArr. This feels a bit hacky, but it works.

How can I add an additional binding to an element inside a dom-repeat?

I have a template dom-repeat element. I know that I can define the items attribute from an array, so that item can be accessed inside the template. However, I don't know how to access other objects inside the template if I bind them to customer polymer elements.
In this example, items is being defined by someItems, and item is passed into the element <my-el>. I also have a string mine that I want to pass into <my-el> and use there. I currently have the idea to do this in app-el.html, which contains the dom-repeat template:
app-el.html
<template is="dom-repeat" items="[[someItems]]">
<my-el item=[[item]] mine="[[mine]]"></my-el><br>
</template>
In theory, I would be able to access both in my-el.html like this:
my-el.html
[[item]] [[mine]]
However, when I try to access mine from inside <my-el> it is undefined. How can I correctly pass in this string so I can access it?
An MCVE can be found on this Plunker. Note how the item string is defined inside <my-el> but the mine string is not.
Your data bindings look correct, but there is no mine property for my-app. Did you mean to define <my-app>.myProperty as <my-app>.mine? Changing that property name to mine fixes your problem.
plunker

Ember.js {{#each}} value in html tag?

So I am using Ember.js each helper and I am having trouble putting values where I want them.
Here is what I want my html to look like.
<div id="item0">
item0Value
</div>
But I can't figure out how to write this in the handlebars template.
This is what I tried.
{{#each item in array}}
<div id="item{{item.id}}">
{{item.value}}
</div>
{{/each}}
This gives me an error.
Uncaught Error: Assertion Failed: An error occured while setting up template bindings. Please check for invalid markup or bindings within HTML comments.
Is there a way to do what I want here? or is it not possible to put values inside the html tags?
From ember/guides:
It is often useful to specify a controller to decorate individual
items in the ArrayController while iterating over them. This can be
done by creating an ObjectController:
You can use an item controller to generate the values you need, and then access them in your template:
{{#each item in array itemController="song"}}
<div {{bind-attr="item.cssId"}}>
{{item.value}}
</div>
{{/each}}
// controllers/song
App.SongController = Ember.ObjectController.extend({
cssId: function() {
return 'item' + this.get('id');
}.property('id')
...
Note: As best practice it is better to declare your itemController in the template, and not directly in your ArrayController

Backbone toJSON not rendering

when I use Backbone toJSON method of the model like this:
this.$el.html(this.model.toJSON());
It doesn't render model into view root element ( more than one attribute ).
But when I get one property from the model, like this;
this.$el.html(this.model.get("city"));
It is rendered properly.
Also, when I use template in first case (toJSON) - it is rendered fine.
this.$el.html(this.template(this.model.toJSON());
Why is that ?
Thanks
this.$el.html(this.model.toJSON());
You're using the html method of jQuery, which expects a string (or a DOM element, or a jQuery element), to display a JSON object.
this.$el.html(this.template(this.model.toJSON());
Here you're using a template method which, I assume, is taking a JSON object to evaluate a template that will return you a string. The htmlmethod receives this string and displays it.
this.$el.html(JSON.stringify(this.model.toJSON()));
This would display the result of this.model.toJSON() (but won't do the same as using your template method).
So, basically this.template will be (in most of the cases) a compiled version of the html template which you have for the view.
It will have placeholders in it, and will take parameters with the same key as placeholders in the template. For example (Handlebars templates),
<section id="{{id}}">
<header>{{header_text}}</header>
</section>
Considering the above code as a template, when you compile and store it in this.template, it returns a function, which takes a json object as a parameter, so now this.template is a function.
You can call it like below,
var html_text = this.template({
id : "main_content",
header_text : "Hi Welcome !!"
});
this.$el.html(html_text);
After the execution, el's contents will be
<section id="main_content">
<header>Hi Welcome !!</header>
</section>
So when you do this.$el.html(this.template(this.model.toJSON());, it actually generates the required json parameter for the this.template method for you, hence works fine.
And as Loamhoof said, in this.$el.html(this.model.get("city")); you use the html method which will set the html content of the el based on the property value of the model.