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

时间:2012-10-24 09:29:29

标签: javascript

使用像这样的Handlebars.js模板......

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

......和这样的数据......

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

我想像这样呈现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>

哪种方式最简单?

18 个答案:

答案 0 :(得分:83)

我发现了许多过于复杂的解决方案,并决定使用Handlebars助手编写自己的解决方案。

使用此部分(使用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();
    });

您可以使用{{#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>

并以此结束...

<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!

答案 1 :(得分:30)

我只是有与OP相似的需求 - 带有一组静态选择选项,但是是一个动态选择值。我真的很喜欢@ janjarfalk的解决方案,但是我使用的是node.js并没有拉入jQuery。所以,我根据RegExp将我自己的变体放在一起。希望这对其他人有所帮助。

把手助手:

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

把手模板:

<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>

即使您不使用value属性,也可以调整助手工作 - 只需调整正则表达式来搜索元素文本,然后在匹配的文本之前进行字符串替换。

答案 2 :(得分:17)

我看到了@janjarfalk发布的非常聪明的解决方案,并意识到它对于没有值属性(例如<option>Value</option>)定义的选项不起作用。我的应用程序需要这个,我想要一个用vanilla JavaScript完成性能的助手,所以我想出了以下内容。

除了<option>Both a label and a value</option>之外,此解决方案还将支持<option value="aValue">A label</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;
});

用法:

<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>

答案 3 :(得分:9)

由于上下文的原因,在使用“each”帮助程序构建动态内容时,我遇到了“select block”方法的问题。

这是我的解决方案:

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

模板:

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

答案 4 :(得分:9)

为我工作

<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>

答案 5 :(得分:6)

改进了@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;
});

用法保持不变:

<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>

答案 6 :(得分:2)

我刚遇到这个问题,这是一个解决方案,当选项是动态的时候。

我没有创建一个选择助手,而是创建了一个选项助手,它接受你想要选择的项目的值。

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

在我的模板中。

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

请注意../访问父母的范围,因为selected_value不太可能在items数组中。

干杯。

答案 7 :(得分:2)

我更喜欢使用模板方法。我的意思是选项标签本身的布局是在把手模板中指定的(有人可能会找到它),而不是在javascript帮助器中。块帮助程序内的模板传递给帮助程序脚本,可以通过调用 options.fn()来使用,然后使用您在帮助程序中进行的任何脚本更改。

模板:

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

略有修改的数据(不是必需的,但对我来说更多“现实世界”)

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注册帮助:

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 是我选择为此帮助者命名的

aStatusList 状态对象数组包含多个属性,包括状态值/名称(在大多数情况下,我遇到的情况是状态代码而不是存储的状态名称)

sCurrentStatus 是先前选择的状态代码(不是值),是我希望在此生成的选项列表中选择的选项值。

statusCode 是aStatusList对象中的字符串属性名称,我将测试它是否匹配myStatus是一个aStutusList [loopIndex] [ statusCode ]

  • 字符串选项属性(在本例中为statusCode)仅对对象是必需的 - 选项列表也可以是字符串数组(而不是包含字符串的对象),在这种情况下,您可以省略第三个属性'statusCode '告诉助手什么对象的属性要再次测试。如果你没有传递那个属性,它只会测试列表项本身。
  • 如果未传递sSelectedOptionValue,则将生成列表而不设置任何项目。这将生成与使用 {{#each}} 帮助
  • 几乎相同的列表

答案 8 :(得分:1)

如果您选择的选项很少而且您不想写帮助,那么您可以做以下事情:

//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);

在模板文件中:

<!-- 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>

同样,这可能不是最好的解决方案,但是当你处理的选项非常少而且需要快速解决时,它可能是一个非常快速的解决方案。

答案 9 :(得分:1)

这可能会在模板中占用更多代码,但更容易阅读:

的.js

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

.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>

答案 10 :(得分:1)

今天,我也遇到了一个同样的问题,即我正在创建一个内容管理系统,并获取了我所坚持的帖子的状态以及在寻找解决方案时,我登陆了此页面,我找到了一些相关的答案,因为我m使用服务器端数据,当我使用document.createElement时,未定义抛出错误的文档。

Regex解决方案对我有用,但是我想要一个易于理解的解决方案,它是否冗长,所以我提出了此解决方案。

For Each row As DataGridViewRow In DataGridView2.Rows
    Dim constring As String = "server=AZZAM-PC ; Database= FastFood ; integrated security=true"
    Using con As New SqlConnection(constring)
        Using cmd As New SqlCommand("insert into tblsales (product , qunty , price )values(@product, @qunty, @price)", con)
            cmd.Parameters.AddWithValue("@product", row.Cells("ITEM").Value)
            cmd.Parameters.AddWithValue("@qunty", row.Cells("QTY").Value)
            cmd.Parameters.AddWithValue("@price", row.Cells("AMOUNT").Value)
            con.Open()
            cmd.ExecuteNonQuery()
            con.Close()

        End Using
    End Using
Next

MessageBox.Show("RECORD INSRTED")

模板中的代码以这种方式使用

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

如果我在某个地方错了,请纠正我。

答案 11 :(得分:0)

用于数组

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

答案 12 :(得分:0)

我知道这不能直接回答问题,但是在这种情况下,我将未选择的html选项传递给了模板,并且在渲染之后,我使用jquery来 将json对象指示的值标记为

答案 13 :(得分:0)

数据源

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

助手

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

模板

<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>

答案 14 :(得分:0)

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>

答案 15 :(得分:0)

使用express-handlebars和动态选项的另一个解决方案就是这个。

辅助功能(从所有选项中取出我们想要的选项并将其更改为选中)。

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

把手文件(我只是使用#each inside select来接收我的数据,并像魅力一样工作)。

<select name="justAname">
  {{#select content.campusId}}
    {{#each campus}}
      <option value="{{id}}">{{name}}</option>
    {{/each}}
  {{/select}}
</select>

答案 16 :(得分:0)

@ lazd的回答不适用于<option>中的<optgroup>元素。

selectedIndex对所有<option>进行单调编号,但select.children保留<optgroup> s,select.children[n].children保留<option> s <optgroup> n {当然,每个<optgroup>内的编号重新开始。)

此替代版本适用于<option> s中的<optgroup>元素:

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;
});

答案 17 :(得分:0)

应该提到的是,如果你不关心重复...你可以使用香草把手并首先放置所选的选项,例如:

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