Determining the last loop index in ractive template - ractivejs

Basically I want to this: In Mustache templating is there an elegant way of expressing a comma separated list without the trailing comma? in a Ractive template.
For the object
{
"items": [
{"name": "red"},
{"name": "green"},
{"name": "blue"}
]
}
I want to produce "red, green, blue"
I want to know if I am at the last item, so I can know whether to print the separator. Something like:
{{#items:i}}{{name}} {{#i.is_last}},{{/i}}{{/items}}

Can't easily test this right now, but wouldn't something like the following work?
{{#items:i}}
{{name}} {{ i < (items.length-1) ? "," : "" }}
{{/items}}

Can confirm that Stephen Thomas' answer works. Another option would be to join the array items like so:
ractive = new Ractive({
el: 'body',
template: '{{ items.map( getName ).join( ", " ) }}',
data: {
items: [{ name: 'red' }, { name: 'green' }, { name: 'blue' }],
getName: function ( item ) {
return item.name;
}
}
});

I actually wanted a solution that would allow me to put something more complicated instead of a comma, say, a DOM element. I figured out (another) method that works.
{{#items:i}}
{{name}}{{#(i<(items.length-1))}}, {{/end}}
{{/items}}

Recently #index and #last magic variables are introduced, so the example now becomes more readable:
{{#items}}
{{.name}}{{##index !== #last}}, {{/}}
{{/}}

Related

react-jsonschema-form collapses the size of my array form and cuts off buttons

I've started building a form in react-jsonschema-form and i'm having a lot of difficulty changing it visually.
The form is an array and it has a button to add and remove a set of input boxes.
I've build it as a component in a test project which has no css applied to it so far.
The form will render as a tiny box where there is no room for the buttons (they are cut of as shown below in images).
a single element
a second element
How its supposed to look on react-jsonschema-form playground
A key difference between my array and the sample array is that i'm having two text input elements per array element. I dont know if this could cause it.
I do need to have two input values as its a group of data that is related, and both is required.
This is my code:
//json schema
const schema = {
type: "object",
properties: {
listOfNumbers: {
title: "opret ledig nummerserie",
type: "array",
required: ["nr_fra", "nr_til"],
items: {
properties: {
nr_fra: {
type: "string",
pattern: "^\\d*$",
minLength: 8,
maxLength: 8,
},
nr_til: {
type: "string",
pattern: "^\\d*$",
minLength: 8,
maxLength: 8,
},
},
},
},
},
};
//uiSchema
const uiSchema = {
listOfNumbers: {
"ui:options": {
orderable: false,
},
items: {
//nr_fra: { "ui:options": { label: false } },
//nr_til: { "ui:options": { label: false } },
},
},
}
I'm applying no css to the below form.
// Form
<Form
schema={schema}
uiSchema={uiSchema}
formData={this.state.formData}
onSubmit={(formOutput) => this.handleSubmit(formOutput)}
transformErrors={transformErrors}
/>
I've spent a day and a half on trying to strongarm this, but i could really use some help on how to proceed.
It seems it was css inputs that was needed to solve this.
The below will expand the elements to their proper size/form.
Posting this here for posterity, as this is not accurately documented.
<div className="col-md-offset-3 col-md-6">
<Form schema={schema}
uiSchema={uiSchema}>
</Form>
</div>

How to locales word in side export default?

I have been trying to change the language from English to others,
$t('bascketball')
↑this works inside the template, however I am looking the way that I can change the language of elements inside of export Default.
If you know how to solve it, please advice me.
export default {
name: "Home",
components: {},
data() {
return {
Games: [
keyword: '',
games: [
{
heading: $t('Basketball'),
text:
"Hello Basketball players, want to know about team members. Click Below.",
img:
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQt0Sh97iYcu0kTguhcsW_szWfzolqu1ynGeQ&usqp=CAU",
},
You can do it with one of these:
this.$t('Basketball')
this.$i18n.tc('Basketball')
But because you're calling the API, you cannot do it in data, you can rewrite it to a computed method, like that:
computed: {
games() {
return [
{
heading: this.$t('Basketball'),
text:
"Hello Basketball players, want to know about team members. Click Below.",
img:
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQt0Sh97iYcu0kTguhcsW_szWfzolqu1ynGeQ&usqp=CAU",
}
]
}
}

Accessing a multidimensional array from a parent each's id in Handlebars

I have the data:
priceGroups:
[
{
label: 'rate1",
price: 1.00,
numPeople: 1
},
{
label: 'rate 2",
price: 2.00,
numPeople: 2
},
{
label: 'rate 3",
price: 15.00,
numPeople: 4
},
];
and
labels:
[
'Solo',
'Duo',
'Trio'
'4 People',
'5 People
];
I want to be able to do this:
{{#priceGroups}}
{{for (a = 1; a <= {{this.numPeople}}; ++a)}}
<th>{{label[a]}}</th>
{{/for}}
{{/priceGroups}}
I have tried so much and nothing works.
Please help. It is important.
I think you can just use this:
{{#each priceGroups}}<th>{{label}}</th>{{/each}}
The {{#each priceGroups}} gets you an iteration of the priceGroups array and then each item of the array (which is an object) is presented to the template one after another so you can then reference the {{label}} property in that object.
You don't embed javascript directly into handlerbars templates like you're trying to do.

How to select a template conditionally with Ractive

I'm trying to select a template conditionally. My idea was that I'd be able to have a container (view) with a list of components, where each component would state which template it should use.
{{#view.components}}
{{> {{template.id}} }}
{{/view.components}}
What I'd like to happen is for the partial declaration to resolve {{template.id}} from the component property called id, then resolve the partial.
i.e.
view.components[0].template.id = "fooTemplate" (<script id="fooTemplate" />)
view.components[1].template.id = "barTemplate" (<script id="barTemplate" />)
and ractive to resolve the #view.components block as
{{>fooTemplate}}
{{>barTemplate}}
This {{>template.id}}, tells me it can't resolve template.id.
This {{>{{template.id}} }} tells me it doesn't know anything about t.
Any workaround I could use?
Take a look to the docs: http://docs.ractivejs.org/latest/partials in "Injecting partials".
You could do something like this in the partials:
ractive = new Ractive({
el: myContainer,
template: myTemplate,
partials: {
content: anyBooleanExpression ? fooTemplate: barTemplate,
}
});
You can use the same conditional in the template property:
template: anyBooleanExpression ? fooTemplate: barTemplate,
And even to use more complex conditionals adding a swich block or an anonymous function.
template: function(){ /* you complex logic */ },
Like in this fiddle
You can define your template as below:
{{#view.components}}
{{#FooTemp}}
{{>fooTemplate}}
{{/FooTemp}}
{{#BarTemp}}
{{>barTemplate}}
{{/BarTemp}}
{{/view.components}}
and your model is like:
{
view: {
components: [
{
FooTemp: { ... }
},
{
BarTemp: { ... }
}
]
}
}

Corresponding Index Into Parallel Array

In Handlebars.js, how can I use #index to subscript into another parallel array in the object I am passing to a template?
For example, say I have an object set up like the following:
var table = {
cols : [
{ name: "Column 1" },
{ name: "Column 2" },
{ name: "Column 3", highlighted: true }
],
rows : [
{
label: "Row 1",
data: [
{ val: 5 },
{ val: 3 },
{ val: 8 }
]
},
{
label: "Row 2",
data: [
{ val: 8 },
{ val: 4 },
{ val: 0 }
]
}
]
};
I need to be able to use the #index from an {{#each rows}}{{#each data}} loop to check if the column is highlighted to apply a style to cells in the column, but Handlebars.js does not appear to allow using #index in a subscript operator.
E.g.
{{#index}} <!-- Index of current rows.data is 2. -->
{{#if ../../cols.[#index].highlighted }}
<!-- Never Executed -->
{{/if}}
{{#if ../../cols.[2].highlighted }}
<!-- Executes -->
{{/if}}
Is this not supported? Am I doing something wrong? How can I get this to work easily?
I posted an example on jsfiddle.net.
#key and #index behave specially, not as variables. So, even when you can use myvar.[123] you cannot use myvar.[#key] even though #key is 123. (At least, as of Handlebars 1.3.0)
There are two solutions. The first is to write your own handlebars helper, that takes both arrays/objects. The second is to restructure your data, i.e. merge your two parallel arrays.
As an example of the latter approach, if you have these two arrays:
var X={
cat:"meow",
sheep:"baaa"
};
var Y={
cat:3,
sheep:5
};
Then you could do:
var Z={};
for(var ix in X){
Z[ix]={X:X[ix],Y:Y[ix]};
}
And then pass Z to your handlebars template:
myTemplate({animals:Z});
which might look like this:
{{#each animals}}
The {{#key}} goes {{this.X}}; we have {{this.Y}} of them.
{{/each}}

Resources