In a handlebars template, how do you set a radio button group to the right value using only the template? Can this be done directly in the template?
For an example,
I really liked the answer from ChrisV, once I understood it. I really struggled to get there from here. Please consider this a supporting comment to the answers above. I will say my use case was a tiny bit different. I'm using Express and I wanted to set the checkbox from a route. It wasn't totally clear to me how to call the helper function. Obviously, I'm using two different radio button groupings.
In app.js, where I initially setup the view engine
var hbs = require('hbs');
hbs.registerPartials(__dirname + '/views/partials');
hbs.registerHelper('checked', function (value, test) {
if (value == undefined) return '';
return value == test ? 'checked' : '';
});
app.set('view engine', 'hbs');
I set the route in index.js
var express = require('express');
var router = express.Router();
router.get('/display_form', function (req, res, next) {
//... play with data. use req.query.optionsRadiosA, etc...
// var outputA = "video"
res.render('formpage', {
title: 'Setup Page',
optionsRadiosA: outputA, // use variable
optionsRadiosB: 'Audio' // or use string
});
});
and finally, my template, formpage.hbs (extract shown...)
<h1>{{title}}</h1>
<form class="pure-form">
<h2>Channel A Setup</h2>
<label for="option-A1">
<input id="option-A1" type="radio" name="optionsRadiosA" value="Video" {{checked optionsRadiosA 'Video'}}> Video
</label>
<label for="option-A2">
<input id="option-A2" type="radio" name="optionsRadiosA" value="Audio" {{checked optionsRadiosA 'Audio'}}> Audio
</label>
<h2>Channel B Setup</h2>
<label for="option-B1">
<input id="option-B1" type="radio" name="optionsRadiosB" value="Video" {{checked optionsRadiosB 'Video'}}> Video
</label>
<label for="option-B2">
<input id="option-B2" type="radio" name="optionsRadiosB" value="Audio" {{checked optionsRadiosB 'Audio'}}> Audio
</label>
<input type="submit" value="Update the Channel Feeds">
</form>
My own solution is:
helper:
Handlebars.registerHelper ("setRadio", function (value, options) {
var $el = $(options.fn(this));
if ( value == $el.val() ) {
return $el.attr("checked", "checked")[0].outerHTML;
} else {
return options.fn(this);
}
Usage in template:
{{#setRadio stars}}<input class="star-rating__input" id="{{id}}-star-rating-5" type="radio" name="{{id}}" value="5" >{{/setRadio}}
<label class="star-rating__ico fa fa-star-o fa-lg" for="{{id}}-star-rating-5" title="5 out of 5 stars"></label>
{{#setRadio stars}}<input class="star-rating__input" id="{{id}}-star-rating-4" type="radio" name="{{id}}" value="4">{{/setRadio}}
<label class="star-rating__ico fa fa-star-o fa-lg" for="{{id}}-star-rating-4" title="4 out of 5 stars"></label>
{{#setRadio stars}}<input class="star-rating__input" id="{{id}}-star-rating-3" type="radio" name="{{id}}" value="3">{{/setRadio}}
<label class="star-rating__ico fa fa-star-o fa-lg" for="{{id}}-star-rating-3" title="3 out of 5 stars"></label>
{{#setRadio stars}}<input class="star-rating__input" id="{{id}}-star-rating-2" type="radio" name="{{id}}" value="2">{{/setRadio}}
<label class="star-rating__ico fa fa-star-o fa-lg" for="{{id}}-star-rating-2" title="2 out of 5 stars"></label>
{{#setRadio stars}}<input class="star-rating__input" id="{{id}}-star-rating-1" type="radio" name="{{id}}" value="1">{{/setRadio}}
<label class="star-rating__ico fa fa-star-o fa-lg" for="{{id}}-star-rating-1" title="1 out of 5 stars"></label>
You can write a helper function to help you with this use case. I like to keep all my block helpers in a designated JS file - but you can put them anywhere inside your scripts.
Handlebars.registerHelper ("setChecked", function (value, currentValue) {
if ( value == currentValue ) {
return "checked";
} else {
return "";
}
});
and in your template you would use it like this:
<label><input type="radio" name="mode" value="auto" {{{setChecked auto mode}}}>Auto</label><br>
<label><input type="radio" name="mode" value="on" {{{setChecked on mode}}}>On</label><br>
<label><input type="radio" name="mode" value="off" {{{setChecked off mode}}}>Off</label><br>
This should work.
This link is a good starting point to block helpers: http://handlebarsjs.com/block_helpers.html
Late addition for anyone else wanting the same: this works (quotes, undefined values, and all):
Handlebars.registerHelper('checked', function(value, test) {
if (value == undefined) return '';
return value==test ? 'checked' : '';
});
Assuming a variable with the name of the input is passed to the Handlebars context, it is used as:
<input type="radio" name="mode" value="auto" {{checked mode 'auto'}}>Auto<br>
<input type="radio" name="mode" value="on" {{checked mode 'on'}}>On<br>
<input type="radio" name="mode" value="off" {{checked mode 'off'}}>Off<br>
Alternatively...
If you don’t like having the helper calls in each input, you could wrap the inputs in a helper as follows:
Handlebars.registerHelper('checked', function(value, options) {
const div = document.createElement('div'); // create a container div
div.innerHTML = options.fn(this); // parse content into dom
div.querySelectorAll('input[type=radio]').forEach(function(input) {
// if input has value matching supplied value, check it
if (input.value == value) input.defaultChecked = true;
});
return div.innerHTML;
});
Which would then be used as follows:
{{#checked mode}}
<input type="radio" name="mode" value="auto">Auto<br>
<input type="radio" name="mode" value="on">On<br>
<input type="radio" name="mode" value="off">Off<br>
{{/checked}}
Note a slightly different approach would be required for checkboxes, as they can have multiple values set.
Remember helpers take precedence over context variables, so if you had an input named ‘checked’, you would have to use a path reference e.g. {{./checked}}
.