简体   繁体   English

如何在 Handlebars 模板中设置选定的选择选项

[英]How to set selected select option in Handlebars template

With a Handlebars.js template like this...使用这样的 Handlebars.js 模板...

<select>
    <option value="Completed">Completed</option>
    <option value="OverDue">OverDue</option>
    <option value="SentToPayer">SentToPayer</option>
    <option value="None">None</option>
</select>

... and data like this... ......和这样的数据......

{
    "id"     : 1,
    "name"   : "World"
    "status" : "OverDue",
    "date"   : "2012-12-21"
}

I want to render HTML like this.我想像这样呈现 HTML。

<select>
    <option value="Completed">Completed</option>
    <option value="OverDue" selected="selected">OverDue</option>
    <option value="SentToPayer">SentToPayer</option>
    <option value="None">None</option>
</select>

Which way is the easiest?哪种方式最简单?

I found a lot of over complicated solutions and decided to write my own using a Handlebars helper.我发现了很多过于复杂的解决方案,并决定使用 Handlebars 助手编写自己的解决方案。

With this partial (using Jquery) ...有了这个部分(使用 Jquery)...

    window.Handlebars.registerHelper('select', function( value, options ){
        var $el = $('<select />').html( options.fn(this) );
        $el.find('[value="' + value + '"]').attr({'selected':'selected'});
        return $el.html();
    });

You can wrap selects in your Handlebars template with {{#select status}}...您可以使用 {{#select status}}... 在 Handlebars 模板中包装选择

<select>
    {{#select status}}
    <option value="Completed">Completed</option>
    <option value="OverDue">OverDue</option>
    <option value="SentToPayer">SentToPayer</option>
    <option value="None">None</option>
    {{/select}}
</select>

and end up with this...并最终得到这个......

<select>
    <option value="Completed">Completed</option>
    <option value="OverDue" selected="selected">OverDue</option>
    <option value="SentToPayer">SentToPayer</option>
    <option value="None">None</option>
</select>

Presto!快!

I just had a similar need as the OP--with a static set of select options, but a dynamic selected value.我只是有一个与 OP 类似的需求——有一组静态的选择选项,但有一个动态的选择值。 I really like @janjarfalk's solution, but I'm using node.js and don't have jQuery pulled in. So, I put together my own variation based on RegExp's.我真的很喜欢@janjarfalk 的解决方案,但我使用的是 node.js 并且没有引入 jQuery。所以,我根据 RegExp 组合了我自己的变体。 Hope this is helpful to others.希望这对其他人有帮助。

Handlebars helper:车把助手:

hbs.registerHelper('select', function(selected, options) {
    return options.fn(this).replace(
        new RegExp(' value=\"' + selected + '\"'),
        '$& selected="selected"');
});

Handlebars template:车把模板:

<select>
    {{#select CurrentSort}}
    <option value="1">Most Recent First</option>
    <option value="2">Most Recent Last</option>
    <option value="3">Highest Score First</option>
    <option value="4">Highest Score Last</option>
    <option value="5">Most Comments</option>
    <option value="6">Fewest Comments</option>
    <option value="7">Most Helpful Votes</option>
    <option value="8">Fewest Helpful Votes</option>
    {{/select}}
</select>

You can tweak the helper to work even if you don't use the value attribute--just adjust the regexp to search the element text, and do the string replacement before the matched text.即使您不使用value属性,您也可以调整助手使其工作——只需调整正则表达式以搜索元素文本,并在匹配文本之前进行字符串替换。

I saw the extremely clever solution posted by @janjarfalk and realized it didn't work for options defined without a value attribute (such as <option>Value</option> ).我看到了@janjarfalk 发布的非常聪明的解决方案,并意识到它不适用于没有 value 属性定义的选项(例如<option>Value</option> )。 My application needed that, and I wanted a helper done in vanilla JavaScript for performance, so I came up with the following.我的应用程序需要它,并且我想要一个在 vanilla JavaScript 中完成的帮助程序以提高性能,所以我想出了以下内容。

This solution will support <option>Both a label and a value</option> in addition to <option value="aValue">A label</option> and will be much faster as it doesn't use jQuery.除了<option value="aValue">A label</option>之外,这个解决方案将支持<option>Both a label and a value</option> ,并且由于它不使用jQuery,所以速度会快得多。

Handlebars.registerHelper('select', function(value, options) {
    // Create a select element 
    var select = document.createElement('select');

    // Populate it with the option HTML
    select.innerHTML = options.fn(this);

    // Set the value
    select.value = value;

    // Find the selected node, if it exists, add the selected attribute to it
    if (select.children[select.selectedIndex])
        select.children[select.selectedIndex].setAttribute('selected', 'selected');

    return select.innerHTML;
});

Usage:用法:

<select>
    {{#select status}}
    <option>Option 1</option>
    <option>Option 2</option>
    <option value="Option 3">Option 3 (extra info)</option>
    <option value="Option 4">Option 4 (more extra)</option>
    {{/select}}
</select>

Works for me为我工作

<select>
    <option value="{{status}}" hidden="hidden" selected="selected">{{status}}</option>
    <option value="Completed">Completed</option>
    <option value="OverDue">OverDue</option>
    <option value="SentToPayer">SentToPayer</option>
    <option value="None">None</option>
</select>

I've had problems with the "select block" approach when using the "each" helper to build something dynamic, due to the context.由于上下文的原因,我在使用“每个”帮助程序构建动态内容时遇到了“选择块”方法的问题。

Here is my solution:这是我的解决方案:

  Handlebars.registerHelper('option', function(value, label, selectedValue) {
    var selectedProperty = value == selectedValue ? 'selected="selected"' : '';
    return new Handlebars.SafeString('<option value="' + value + '"' +  selectedProperty + '>' + label + "</option>");
  });

And the template:和模板:

<select>
  {{#each status}}
    {{option id name ../statusId}}
  {{/each}}
</select>

Improved answer of @lazd to select first option when nothing matches.改进了@lazd 的答案,以便在没有匹配项时选择第一个选项。

Handlebars.registerHelper('select', function(value, options) {
    // Create a select element 
    var select = document.createElement('select');


// Populate it with the option HTML
$(select).html(options.fn(this));

//below statement doesn't work in IE9 so used the above one
//select.innerHTML = options.fn(this); 

    // Set the value
    select.value = value;

    // Find the selected node, if it exists, add the selected attribute to it
    if (select.children[select.selectedIndex]) {
        select.children[select.selectedIndex].setAttribute('selected', 'selected');
    } else { //select first option if that exists
        if (select.children[0]) {
            select.children[0].setAttribute('selected', 'selected');
        }
    }
    return select.innerHTML;
});

Usage remains same:用法保持不变:

<select>
    {{#select status}}
    <option>Option 1</option>
    <option>Option 2</option>
    <option value="Option 3">Option 3 (extra info)</option>
    <option value="Option 4">Option 4 (more extra)</option>
    {{/select}}
</select>

This might take more code in the template, but it is easier to read:这可能会在模板中占用更多代码,但更易于阅读:

.js .js

Handlebars.registerHelper('select', function(selected, option) {
    return (selected == option) ? 'selected="selected"' : '';
});

.hbs .hbs

<select name="status">
    <option value="public" {{{select story.status 'public'}}}>Public</option>
    <option value="private" {{{select story.status 'private'}}}>Private</option>
    <option value="unpublished" {{{select story.status 'unpublished'}}}>Unpublished</option>
</select>

I just ran into this problem, here's a solution for when the options are dynamic..我刚刚遇到这个问题,这是一个解决方案,适用于选项是动态的。

Instead of creating a select helper, I created an option helper that accepts the value of the item you wish to be selected.我没有创建选择助手,而是创建了一个选项助手,它接受您希望选择的项目的值。

Handlebars.registerHelper('option', function(value) {
  var selected = value.toLowerCase() === (this.toString()).toLowerCase() ? 'selected="selected"' : '';
  return '<option value="' + this + '" ' + selected + '>' + this + '</option>';
});

And in my template.在我的模板中。

{{#items}}
    {{{option ../selected_value}}}
{{/items}}

Please note the ../ to access the parent's scope as it's not likely the selected_value will be inside of the items array.请注意 ../ 访问父级的范围,因为 selected_value 不太可能在 items 数组内。

Cheers.干杯。

I prefer to use a template approach.我更喜欢使用模板方法。 By this I mean the layout of the option tag itself is specified in the handlebars template (where someone might look for it) and not in the javascript helper.我的意思是选项标签本身的布局是在车把模板中指定的(有人可能会在那里寻找它),而不是在 javascript 助手中。 Template inside the block helper is passed into the helper script and can be used by calling options.fn() which then uses any script changes you have made in your helper.块助手内的模板被传递到助手脚本中,可以通过调用options.fn()使用,然后使用您在助手中所做的任何脚本更改。

Template:模板:

<select>
  {{#optionsList aStatusList sCurrentStatusCode 'statusCode'}}
    <option {{isSelected}} value="{{statusCode}}">{{statusName}}</option>
  {{/optionsList}}
</select>

Slightly modified data (not required but a little more "real world" for me)稍微修改的数据(不是必需的,但对我来说更“真实”)

var myOrder = 
{
    "id"     : 1,
    "name"   : "World",
    "statusName" : "OverDue", /* status should NOT be here! */
    "statusCode" : "1",
    "date"   : "2012-12-21"
}

var sCurrentStatusCode = myOrder.statusCode;

var aStatusList =
[
    {
        "statusName"       : "Node",
        "statusCode" : 0
    },
    {
        "statusName"       : "Overdue",
        "statusCode" : 1
    },
    {
        "statusName"       : "Completed",
        "statusCode" : 2
    },
    {
        "statusName"       : "Sent to Payer",
        "statusCode" : 3
     }
]

Javascript registered helper: Javascript 注册助手:

Handlebars.registerHelper( 'optionsList',
function ( aOptions, sSelectedOptionValue, sOptionProperty, options )
{
  var out = "";
  for ( var i = 0, l = aOptions.length; i < l; i++ )
  {
    aOptions[ i ].isSelected = '';
    if( ( sOptionProperty != null &&  sSelectedOptionValue == aOptions[ i ][ sOptionProperty ] ) || (  sSelectedOptionValue == aOptions[ i ] ) )
    {
      aOptions[ i ].isSelected = ' selected="selected" ';
    }
    out = out + options.fn( aOptions[ i ] );
  }
  return out;
} );

optionsList is what I have chosen to name this helper optionsList是我选择为这个助手命名的

aStatusList an array of status objects contain several properties including the status value/name (in most cases I have encountered this would be the status code not the status name that is stored ) aStatusList一个状态对象数组包含几个属性,包括状态值/名称(在大多数情况下,我遇到过这将是状态代码而不是存储的状态名称)

sCurrentStatus is the previously selected status code (not the value) and is the option value that i would like to have the selected in this generated option list. sCurrentStatus是先前选择的状态代码(不是值),是我希望在此生成的选项列表中选择的选项值。

statusCode is the string property name within a aStatusList object that I will test to see if it matches myStatus that is aStutusList[ loopIndex ][ statusCode ] statusCode是 aStatusList 对象中的字符串属性名称,我将测试它以查看它是否与 myStatus 匹配,即 aStutusList[ loopIndex ][ statusCode ]

  • the string option property ( statusCode in this case ) is only required for objects -- options lists may also be arrays of strings (instead of objects that in turn containing strings) in which case you may omit the the third property 'statusCode' which tells the helper what property of the object to test agains.字符串选项属性(在本例中为 statusCode )仅适用于对象——选项列表也可能是字符串数组(而不是包含字符串的对象),在这种情况下,您可以省略第三个属性“statusCode”,它告诉帮助程序再次测试对象的什么属性。 If you don't pass that property it will just test againts the list item itself.如果您不传递该属性,它只会再次测试列表项本身。
  • if the sSelectedOptionValue is not passed then the list will be produced without setting any item to selected.如果未通过 sSelectedOptionValue,则将生成列表而不将任何项目设置为选定。 This will generate the list pretty much the same as using the {{#each}} helper这将生成与使用{{#each}}助手几乎相同的列表

If you have very few options and you don't want to write a helper, here is what you can do:如果您的选择很少,并且不想编写帮助程序,则可以执行以下操作:

//app.js
var data = {selectedVal: 'b'}; 

// can also use switch ... case ...
if (data.selectedVal === 'a') {
   data.optionASelected = true;
} else if (data.selectedVal === 'b') {
   data.optionBSelected = true;
}

// assuming you have a template function to handle this data
templateFunc(data);

In your template file:在您的模板文件中:

<!-- template.html -->
<select id="select-wo-helper" >
  <option value="a" {{#if optionASelected}} selected {{/if}}>A</option>
  <option value="b" {{#if optionBSelected}} selected {{/if}}>B</option>
</select>

Again this may NOT be the best solution of all, but it probably is a very quick work around when you are dealing very few options and wanted a quick fix.同样,这可能不是最好的解决方案,但是当您处理很少的选项并想要快速修复时,它可能是一个非常快速的解决方法。

Today I was also facing the same problem I'm creating a Content Management System and to fetch the status of the post I stuck and in searching for a solution, I landed on this page I found a few answers relevant Because I'm using server-side data and when I used document.createElement it is throwing error document is not defined.今天我也面临同样的问题我正在创建一个内容管理系统并获取我卡住的帖子的状态并寻找解决方案,我登陆此页面我找到了一些相关的答案因为我正在使用服务器- 端数据,当我使用 document.createElement 时,它抛出错误文档未定义。

The Regex solution worked for me but I want an easy to understand one whether it is verbose so I came with this solution. Regex 解决方案对我有用,但我想要一个易于理解的解决方案,无论它是否冗长,所以我提供了这个解决方案。

 Handlebars.registerHelper('getValue', function(value, options) {
   if(options.fn(this).indexOf(value) >= 1){
         return `selected='selected'`;
      }
});

in the template use the code in this way在模板中以这种方式使用代码

  <select name="post-status" id="post-status">
        <option {{#getValue posts.postStatus}} value="Draft" {{/getValue}} >Draft</option>
        <option {{#getValue posts.postStatus}} value="private" {{/getValue}} >private</option>
        <option {{#getValue posts.postStatus}} value="publish" {{/getValue}} >publish</option>
</select>

If I'm wrong somewhere Please correct me.如果我在某处错了,请纠正我。

Data source数据源

selectedValue: "8",
option:[
    {id_sub_proyectop: "8", clave: "021", name: "Cliclismo"},
    {id_sub_proyectop: "9", clave: "022", name: "Atletismo"},
],

helper帮手

Handlebars.registerHelper('selected', function(value, prop) {
    if (value === undefined){ return '';};
    return value === this[prop] ? 'selected="selected"' : '';
});

Template模板

<div class="medium-6 cell">
    <label>Sub Proyecto / Proceso:
        <select name="id_sub_proyectop" required>
            {{#each option}}
            <option value="{{id_sub_proyectop}}" {{{selected ../selectedValue 'id_sub_proyectop'}}}>{{clave}} - {{name}}</option>
            {{/each}}
        </select>
    </label>
</div>

It should be mentioned that if you do not care about repeats... you can just use vanilla handlebars and place the selected option first, such as:应该提到的是,如果您不关心重复...您可以使用香草车把并首先放置所选选项,例如:

        <select name="ingredient">
        <option value="{{ingredient.id}}" selected>{{ingredient.name}}</option>
        {{#each ingredients}}
        <option value="{{this.id}}">{{this.name}}</option>
        {{/each}}
        </select>

@lazd's answer does not work for <option> elements within an <optgroup> . @lazd 的答案不适用于<optgroup> <option>元素。

selectedIndex is numbered monotonically for all <option> s, but select.children holds the <optgroup> s, and select.children[n].children holds the <option> s within <optgroup> n (with numbering restarting within each <optgroup> , of course). selectedIndex对所有<option> s 单调编号,但select.children持有<optgroup> s,而select.children[n].children <optgroup><optgroup> n 内持有<option> s(在每个<optgroup>内重新编号<optgroup> ,当然)。

This alternative version will work for <option> elements within <optgroup> s:此替代版本适用于<optgroup><option>元素:

Handlebars.registerHelper('select-optgrp', function(value, options) {
    var select = document.createElement('select'); // create a select element
    select.innerHTML = options.fn(this);           // populate it with the option HTML
    select.value = value;                          // set the value
    var g = 0, i = select.selectedIndex;           // calculate which index of which optgroup
    while (i >= select.children[g].children.length) { i -= select.children[g].children.length; g++; }
    if (select.children[g].children[i]) {          // if selected node exists add 'selected' attribute
        select.children[g].children[i].setAttribute('selected', true);
    }
    return select.innerHTML;
});

Another one solution using express-handlebars and dynamic options is this.另一个使用express-handlebars和动态选项的解决方案是这样的。

Helper function (From all options takes the one we want and change it to selected).辅助功能(从所有选项中选择我们想要的并将其更改为选中)。

select: function(selected, options) {
    return options.fn(this)
      .replace( new RegExp(' value=\"' + selected + '\"'), '$& selected="selected"')
      .replace( new RegExp('>' + selected + '</option>'), ' selected="selected"$&');
  }

handlebars file (I just use #each inside select to receive me data and worked like a charm). handlebars 文件(我只是在 select 中使用 #each 来接收我的数据并像魅力一样工作)。

<select name="justAname">
  {{#select content.campusId}}
    {{#each campus}}
      <option value="{{id}}">{{name}}</option>
    {{/each}}
  {{/select}}
</select>
Handlebars.registerHelper('select', function( value, options ){
  return options.fn(this)
  .replace( new RegExp(' value=\"' + value + '\"'), '$& selected="selected"')
  .replace( new RegExp('>' + value + '</option>'), ' selected="selected"$&');
});

user.country from db session
country stored in country.json file

<select id="country" name="country" class="form-control">
<option value="" selected="selected">(please select a country)</option>
{{#select user.country}}
{{#each countries as |value key| }}
<option value="{{ value.code }}">{{ value.name }}</option>
{{/each}}
{{/select}}
</select>

我知道这并没有直接回答问题,但在这种情况下,我将未选择的 html 选项传递给模板,并在呈现后,我使用 jquery 将 json 对象指示的值标记为已选择

for arrays对于数组

function select(selected, options) {
    return options.fn(this).replace( new RegExp(' value=\"' + selected + '\"'), '$& selected="selected"').replace( new RegExp('>' + selected + '</option>'), ' selected="selected"$&');
  },

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM