Как установить выбранную опцию выбора в шаблоне Handlebars

С шаблоном 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>

Какой путь самый простой?

Ответ 1

Я нашел много сложных решений и решил написать свой собственный с помощью помощника 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();
    });

Вы можете обернуть выделение в вашем шаблоне Handlebars с помощью {{#select status}}...

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

Ответ 2

У меня была аналогичная потребность в OP - со статическим набором параметров выбора, но с динамическим выбранным значением. Мне очень нравится решение @janjarfalk, но я использую node.js и не вставляю jQuery. Итак, я собрал свои собственные варианты, основанные на RegExp. Надеюсь, что это полезно для других.

Помощник Handlebars:

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

Шаблон Handlebars:

<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 - просто настройте регулярное выражение для поиска текста элемента и выполните замену строки перед совпадающим текстом.

Ответ 3

Я увидел чрезвычайно умное решение, отправленное @janjarfalk, и понял, что он не работает для опций, определенных без атрибута value (например, <option>Value</option>). Мое приложение нуждалось в этом, и я хотел, чтобы хелпер, выполненный в ванильном 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>

Ответ 4

У меня были проблемы с подходом "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>

Ответ 5

Улучшен ответ @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

Я просто столкнулся с этой проблемой, вот решение, когда параметры динамические.

Вместо создания вспомогательного элемента select я создал вспомогательный параметр, который принимает значение элемента, который вы хотите выбрать.

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

Обратите внимание, что../для доступа к родительской области, так как это вряд ли будет выбрано_значение будет внутри массива элементов.

Приветствия.

Ответ 7

Я предпочитаю использовать шаблонный подход. Под этим я подразумеваю, что макет самого тега параметра задается в шаблоне дескрипторов (где кто-то может его искать), а не в помощнике javascript. Шаблон внутри вспомогательного блока передается в помощник script и может быть использован при вызове options.fn(), который затем использует любые изменения script, внесенные вами в ваш помощник.

Шаблон:

<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

Если у вас очень мало вариантов, и вы не хотите писать помощника, вот что вы можете сделать:

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

Работает для меня

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

Ответ 10

Следует отметить, что если вам не нужны повторы... вы можете просто использовать ванильные рули и сначала поместить выбранный параметр, например:

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

Ответ 11

@lazd ответ не работает для <option> элементов в <optgroup>.

selectedIndex пронумерована монотонно для всех <option> s, но select.children содержит <optgroup> s, а select.children[n].children содержит <option> внутри <optgroup> n (с перезапуском нумерации в каждом <optgroup>, конечно).

Эта альтернативная версия будет работать для <option> элементов внутри <optgroup> s:

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

Ответ 12

Это может занять больше кода в шаблоне, но его легче читать:

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

Ответ 13

Еще одно решение с использованием express-handlebars и динамических параметров.

Функция помощника (из всех параметров берем тот, который мы хотим, и меняем его на выбранный).

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

файл handlebars (я просто использую #each внутри select, чтобы получать данные и работать как шарм).

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