I'm writing a fun little project to build up my HTML/JS skills. I'm using Handlebars to render some forms, and I hit something I can't seem to get around.
I've registered this as a partial template named 'checkbox':
<label>
<input
type="checkbox"
id="{{id}}"
name="{{id}}"
value="true">
{{labelText}}
</label>
That did me well when I was making forms to add data, but now I'm making forms to edit data, so I want to make the checkbox checked if the current item already is checked. I can't figure out how to make this work.
The first thing I tried was something like this:
<label>
<input
type="checkbox"
id="{{id}}"
name="{{id}}"
value="true"
checked="{{isChecked}}">
{{labelText}}
</label>
But if I pass that values like isChecked=true I get a checked box every time, because I guess for that kind of attribute in HTML being present at all means 'true'. OK.
So I tried using the if helper:
<input
type="checkbox"
id="{{id}}"
name="{{id}}"
value="true"
{{#if isChecked}}checked{{/if}}>
{{labelText}}
This sort of works. If I omit the isChecked property entirely, the box is unchecked. If I hard-code a true or false value like this, it works:
{{> checkbox id="test" labelText="test" isChecked=true }}
But I can't seem to get what I want with a value there. For example, if I try:
{{> checkbox id="test" labelText="test" isChecked="{{someCondition}}" }}
It seems like the condition isn't properly being resolved because I always get the attribute in that case.
What am I missing? I feel like there should be a way to do this, but I'm running out of tricks.
You cannot put an expression inside of another expression:
{{> checkbox id="test" labelText="test" isChecked="{{someCondition}}" }}
From examples you wrote I assume the problem you are having is related to how you pass the context - id and labelText are hardcoded while isChecked is expected to be a variable of some sort. In reality all those should be variables. Consider the following example - HTML:
<div id="content"></div>
<script id="parent-template" type="text/x-handlebars-template">
{{#each checkboxes}}
{{> checkbox this }}<br>
{{/each}}
</script>
<script id="partial-template" type="text/x-handlebars-template">
<input
type="checkbox"
id="{{id}}"
name="{{id}}"
value="true"
{{#if isChecked}}checked{{/if}}>
{{labelText}}
</script>
JS:
var parentTemplate = Handlebars.compile($("#parent-template").html());
Handlebars.registerPartial({
checkbox: Handlebars.compile($("#partial-template").html())
});
$('#content').html(parentTemplate(
{checkboxes: [
{id: 1, labelText: "test 1", isChecked: true},
{id: 2, labelText: "test 2", isChecked: false},
]}
));
Related
So I have an easy-search template:
<template name="searchBox">
<div class="">
{{> EasySearch.Autosuggest index=PlayersIndex }}
</div>
</template>
And I'd like to make the input field look like this (have the following attributes):
<input
type="text"
placeholder="Type to add new player"
ref="textInput"
/>
I've tried adding the attributes to the argument but that doesn't seem to work:
{{> EasySearch.Autosuggest index=PlayersIndex type="text"}}
Any ideas how to achieve this?
Just add attributes property in your HTML:
{{> EasySearch.Input index=index attributes=inputAttributes}}
And in your JS, fill it with your needed data:
`Template.leaderboard.helpers({
inputAttributes: function () {
return { 'class': 'easy-search-input', 'placeholder': 'Start searching...' };
}
)}
`
I was able to find the answer by looking at this repo, so make sure to check github repos as they might contain helpful examples. ;)
I want to include a Blaze template with an argument and then use the argument value in an event. The problem is that when I include the template a second time with a different argument I get the argument value from the first instance of the template in events.
Template:
<template name="UploadFormLayoutImage">
<form class="uploadPanel">
<input type="file" name="fileupload" id="input-field">
<label for="input-field">Upload file</label>
</form>
</template>
Include:
{> UploadFormLayoutImage layoutArea="area1"}}
{> UploadFormLayoutImage layoutArea="area2"}}
js:
Template.UploadFormLayoutImage.onCreated(function(){
this.currentArea = new ReactiveVar;
this.currentArea.set(this.data.layoutArea);
});
Template.UploadFormLayoutImage.helpers({
layoutArea: function() {
return Template.instance().currentArea.get(); //Returns the correct argument value for each instance of the template.
}
});
Template.UploadFormLayoutImage.events({
'change input[type="file"]': function(e, instance) {
e.preventDefault();
console.log(instance.data.layoutArea); //Allways returns 'area1'
}
});
What am I missing here? (This is my first Stackoverflow question. Please be gentle :))
What if you change the instance.data.layoutArea in your events method to this.layoutArea?
In my effort to make the code example easy to read i stripped away the part that caused the problem. I'm using a label for the input field and therefore the input field has an id and thats of course not ok when repeating the template.
I now use the layoutArea-helper as an id value and every thing works just fine.
<template name="UploadFormLayoutImage">
<form class="uploadPanel">
<input type="file" name="fileupload" id="{{layoutArea}}">
<label for="{{layoutArea}}">Upload file</label>
</form>
</template>
When I bind a boolean variable to radio buttons with true/false values, the radio buttons' checked status does not get set when the template first loads -- both remain unchecked.
new Ractive({
template: "#template",
el: "#output",
data: {
accept: true
}
});
<script src="//cdn.ractivejs.org/latest/ractive.js"></script>
<div id="output"></div>
<script id="template" type="text/html">
<input type="radio" name="{{ accept }}" value="true" /> Yes
<input type="radio" name="{{ accept }}" value="false" /> No
<br/>
accept = {{ accept }}
</script>
But once I click the radio buttons, their checked statuses do become in sync with the boolean variable.
How can I get this binding to work? Is it a bug with Ractive or am I doing something wrong?
I can work around the problem by changing my boolean variable to a string (accept: "true") but that really wouldn't be ideal.
Computed property will be an overkill for this case. Actually, you were close enough on your original example. Just try the following (only change is at value="{{true}}" instead of value="true"):
new Ractive({
template: "#template",
el: "#output",
data: {
accept: false
},
});
<script src="//cdn.ractivejs.org/latest/ractive.js"></script>
<div id="output"></div>
<script id="template" type="text/html">
<input type="radio" name="{{ accept }}" value="{{true}}"/> Yes
<input type="radio" name="{{ accept }}" value="{{false}}"/> No
<br/>
accept = {{ accept }}
<button on-click="toggle('accept')">toggle</button>
</script>
To my knowledge, ractive types everything hard coded in the template value props of inputs to strings. Illustrated here.
However properties in your data-object does obviously retain their types. Usually multiple different values is what you use radio buttons for anyways. A simple "true/false" bool doesn't need more than a checkbox. Ugly example of binding your radio buttons to bool objects here. (PS: Obviously not recommended).
I'm trying to avoid repetitive template code for forms that are essential the same when creating or editing new items.
For example, something like this:
<template name="createOrEdit">
<form role="form">
<div class="form-group">
<input type="text" class="form-control" id="title" placeholder="Title"/ value="{{title}}">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</template>
<template name="create">
{{> createOrEdit}}
</template>
<template name="edit">
{{> createOrEdit}}
</template>
Then, I could created separate template handlers:
Template.create.events(...
Template.edit.events(...
However, those parent template wrappers won't get the events for the main child template.
Is there a way to do what I want?
Those parent templates can get the events from child template. Use it like this:
Template.create.events({
'click .btn':function(){
}
})
Template.edit.events({
'click .btn':function(){
}
})
In Template.createOrEdit.events object you keep events used by both templates and in Template.edit.events and Template.create.events specific code for each.
see proof and
source code
This approach is really nice as you can customize form by passing some variables:
{{# create btnText="create" }}{{/create}}
{{# edit btnText="update" }}{{/edit}}
And in createOrEdit template you can use variable btnText to change button's label.
I'm curious if I can somehow use dynamic variable names in templates. For example, I'm having a loop, though a type of units in my game:
{{# config.units:unit }}
<input type="text" id="unit_{{unit}}" class="toTrain selectable" value="" placeholder="0" />
{{/ config }}
Where the value of the input should return the value of {{units_1}} for example, which represents the amount of units (type 1).
I could easily do some external object and store the amount of units for each of them but, I was wondering if I can keep the data binded because somewhere in the template there will be a total needed resources which is calculated whith these values.
The only "solution" which came into my head was to get rid of the loop and manually write the units in the template. But, when units change, I also need to change the template, and.. the real template structure for one unit is a bit bigger than this snippet.
Example:
<input value="{{units_1}}" />
<input value="{{units_2}}" />
And I was looking for something like:
<input value="{{'units_'+unit}}" />
Which is obviously not working and not even supposed to work this way. But, thats why I'm here right ? To raise questions.
Regards !
Try to use write getUnit function:
{{# config.units:unit }}
<input type="text" id="{{ getUnit(unit) }}" class="toTrain selectable" value="" placeholder="0" />
{{/ config }}
Component:
Ractive.extend({
init:function(){
self.set("getUnit", function (id) {
return self.get("config.units.unit_"+id);
});
}
})