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

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.

Related

Using 'this' keyword in Angular component's template

Let's say we have a prop variable in the component class and we use it via interpolation in the template (stackblitz demo):
component class:
#Component({...})
export class AppComponent {
prop = 'Test';
...
}
template:
<p>{{ this.prop }}</p>
<p>{{ prop }}</p>
Why in Angular it's possible to use this keyword in templates without any warnings/error (even in AOT mode)? What's behind it?
Edit
According to the remark in the answer: this refers to the component itself for which the template was rendered. But I can also create a template variable and access to it using this:
<input #inp> {{ this.inp.value }}
In this case we don't have an inp variable in the component class and I still get the access to it using {{this.inp...}}. Magic?
I don't think somebody can give a very much exact answer here (maybe somebody from Angular CLI team), however the outcome I came to is that the component renderer fully ignores this keyword in the places where it seems valid (with some exceptions).
Proof
<input #heroInput value="0">
This prints the component JSON without heroInput: {{ this | json }}
<input #heroInput value="0">
This prints 0: {{ this.heroInput.value }}
<div *ngFor="let val of [1,2,3]">
<input #heroInput [value]="val">
Overrides heroInput with current value: {{ this.heroInput.value }}
</div>
This prints 0: {{ this.heroInput.value }}
One can assume from the above that this is similar to AngularJS (angular 1) scope, where the scope contains the component properties.
It does not explain why heroInput is not listed in this | json still.
However the following is totally broken:
{{ this['heroInput'].value }}
It gives an error: cannot get value of undefined. It should, not, it must work, unless (the only explanation) this is just ignored in every case but
{{ this | json }}
where it refers to the component, because this is the only way to debug the whole component object from the template. Maybe there are some other exceptions, still.
Updated stackblitz
this refers to the component itself for which the template was rendered. On the template you can access only members of the component. This means that this is implicitly added to each property which you use in the template.
This two accesses are the same - the 2nd one implicitly use this in front of it.
<p>{{ this.prop }}</p>
<p>{{ prop }}</p>
The same is when you use this in the component. When you want to access prop in the component you need to prefix it with this.prop to inform that you are accessing property of the component, not a local variable.
I felt we can't get a proper explanation on this but,
I went through a case where i will be creating the members of the component dynamically.
In here it might go wrong, if i don't use this.member (In my case it was actually this[member]).
Create a member in component like,
this.members(prop=> this[prop]={})
Usage in template will be like,
{{this[prop]}} will give expected result.
{{prop}} will not give expected result because
it will print value of list.

Patterns for collections of polymorphic objects in Polymer?

Say I have two separate lists of polymorphic objects: Shape -> Circle and Shape -> Rectangle. Shape contains the properties "name" and "description", while Circle contains the properties "center" and "radius" and rectangle contains "length" and "width" properties. I'd like to have a single Polymer component, "shape-list", that would be able to handle display of either the list of Circles or list of Rectangles and display the specific properties of each type in the list.
"shape-list"'s template might look something like so:
<template>
<ul>
<template is="dom-repeat" items="[[shapes]]" as="shape">
<li>
<shape-entry shape="[[shape]]">
<!-- The user of shape-list knows whether we want to display
Rectangles or Circles. We want to customize the display
of each shape-entry with information specific to each
shape by using some sort of prototype element supplied
to the shape-list tag. -->
<content select="..."></content>
</shape-entry>
</li>
</template>
</ul>
</template>
And "shape-entry"'s template would look something like so:
<template>
Name: <span>[[shape.name]]</span>
Description: <span>[[shape.description]]</span>
<!-- Ideally we would take the passed-in prototype element and
stamp it out here. -->
<content select="...?"></content>
</template>
Further, we would have templates for "shape-circle" and "shape-rect":
shape-circle:
<template>
Center: <span>[[shape.center]]</span>
Radius: <span>[[shape.radius]]</span>
</template>
shape-rect:
<template>
Length: <span>[[shape.length]]</span>
Width: <span>[[shape.width]]</span>
</template>
The usage would ideally be something like the following:
I can see two ways of accomplishing the above:
Not using "content" tags, but instead setting a property on the shape-list and shape-entry elements to the actual prototype object reference or name of the specific shape, then having some magic JavaScript that creates an instance of that specific shape element based on that property and manually wiring all of the data binding together. This yields additional complexity to assemble the elements and data binding.
Replicate "shape-list" and "shape-entry" into "rect-list", "circle-list" and "rect-entry", "circle-entry", and share styles and behaviors between the subtypes. This results in some code duplication.
Is there a better way of accomplishing the above? I'd (ideally) prefer an entirely declarative approach!
You could have a shape-list component that uses an "if" template to display the proper shape component (rect-entry, circle-entry ). Each shape entry should declare a shared behavior, e.g ShapeBehavior that has all the shared shape behavior to avoid duplicity.
.. inside the dom-repeat
<template is="dom-if" if="{{_isRect(item)}}" >
<rect-entry shape={{item}} ></rect-entry>
</template>
<template is="dom-if" if="{{_isCircle(item)}}" >
<circle-entry shape={{item}} ></circle-entry>
</template>
If you want to dynamically pass the element that should be used , then a programatically solution is needed.

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

dynamically pass in template to polymer-element

I have been trying create a polymer-element that generates a ul list based on an ajax request and then renders the "li" elements based on templates that can somehow be passsed in.
It's basically an attempt to make a polymer rebuild of the 'select2' library for autocompletion.
So, the base template I have so far looks like this:
<polymer-element name="auto-complete" attributes="url_base item_template">
<aj-ax id="xhr" url="{{url_base}}" params="{}" handle_as="json" on-ajax-response="{{handle_res}}" on-ajax-error="{{handle_err}}"></aj-ax>
<input id="eingabe" type="text" on-keyup="{{process_request}}" on-blur="{{hide_dropdown}}"/>
<div id="dropdown" hidden?="{{hide}}">
<ul>
<template repeat="{{i in items}}">
<li> i.text
<!--
the process_request handler makes the ajax request and sets
the "items" and un-hides the dropdown.
the above works, but I want to make it more generic so that
you can pass in a template that reads the item model such as
<template ref="{{item_template}}" bind></template>
where item_template is the ID of a template in some outside
scope
-->
</li>
</template>
</ul>
</polymer-element >
</div>
I've also tried to make a base auto-complete.html polymer-element and then extend it based on the auto-complete type...but to no avail.
Any thoughts, ideas?
I want to stick to declarative methods if possible and avoid having to build the DOM elements myself with document.createElement
Is that even possible?
thanks!
I've come up with a cool approach to do this actually!
http://jsbin.com/hesejipeha/2/edit
The main idea is that you conditionally render the your template once you've injected any child templates into the shadow DOM (and thus made it possible to call them by ref in scope!)

Handlebars: Accessing JSON Property of Parent using child property

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