最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Using Handlebars.js, how do I populate a select box with global context data but set the selected item with data fr

programmeradmin0浏览0评论

Given the following JSON:

{
    "Colours": [
        { "ColourID": 1, "Name": "Red" },
        { "ColourID": 2, "Name": "Yellow" },
        { "ColourID": 3, "Name": "Blue" }
    ],
    "Sizes": [
        { "SizeID": 1, "Name": "Small" },
        { "SizeID": 2, "Name": "Medium" },
        { "SizeID": 3, "Name": "Large" }
    ],
    "Products": [
        { "ColourID": 1, "SizeID": 1, "Name": "Red Small" },
        { "ColourID": 1, "SizeID": 2, "Name": "Red Medium" },
        { "ColourID": 1, "SizeID": 3, "Name": "Red Large" },
        // and so on...
    ]
}

And the following template HTML:

<table>
    {{#Products}}
    <tr>
        <td>
            <input type="text" value="{{Name}}">
        </td>
        <td>
            <select>
                {{#Colours}}
                <option value="{{ColourID}}">{{Name}}</option>
                {{/Colours}}
            </select>
        </td>
        <td>
            <select>
                {{#Sizes}}
                <option value="{{SizeID}}">{{Name}}</option>
                {{/Sizes}}
            </select>
        </td>
    </tr>
    {{/Products}}
</table>

How can I build the select boxes using the mon colour/size data from the global context, but for each table row set the selected="selected" attribute on the options which have values matching the current product's Colour/Size ID?

As it stands, within the loop there is no access to the Colours or Sizes arrays, so the selects are blank. I've tried using a global helper to explicitly pass them into each product from the global context before rendering, like so:

Handlebars.registerHelper('productloop', function(context, options) {
    var ret = [];

    for(var i=0, j=context.Products.length; i<j; i++) {
        var option = context.Products[i];

        option.Colours = context.Colours;
        option.Sizes = context.Sizes;

        ret.push(options.fn(option));
    }

    return ret.join('');
});

And the HTML:

<table>
    {{#productloop}}
    <tr>
        <td>
            <input type="text" value="{{Name}}">
        </td>
        <td>
            <select>
                {{#Colours}}
                <option value="{{ColourID}}">{{Name}}</option>
                {{/Colours}}
            </select>
        </td>
        <td>
            <select>
                {{#Sizes}}
                <option value="{{SizeID}}">{{Name}}</option>
                {{/Sizes}}
            </select>
        </td>
    </tr>
    {{/productloop}}
</table>

Which does work, but it seems very clunky, and I still have no idea how to set the selected attributes for each product's colour/size select.

Can anyone help me out? I have control over the code which generates the JSON, so the JSON structure can be changed if required.

Given the following JSON:

{
    "Colours": [
        { "ColourID": 1, "Name": "Red" },
        { "ColourID": 2, "Name": "Yellow" },
        { "ColourID": 3, "Name": "Blue" }
    ],
    "Sizes": [
        { "SizeID": 1, "Name": "Small" },
        { "SizeID": 2, "Name": "Medium" },
        { "SizeID": 3, "Name": "Large" }
    ],
    "Products": [
        { "ColourID": 1, "SizeID": 1, "Name": "Red Small" },
        { "ColourID": 1, "SizeID": 2, "Name": "Red Medium" },
        { "ColourID": 1, "SizeID": 3, "Name": "Red Large" },
        // and so on...
    ]
}

And the following template HTML:

<table>
    {{#Products}}
    <tr>
        <td>
            <input type="text" value="{{Name}}">
        </td>
        <td>
            <select>
                {{#Colours}}
                <option value="{{ColourID}}">{{Name}}</option>
                {{/Colours}}
            </select>
        </td>
        <td>
            <select>
                {{#Sizes}}
                <option value="{{SizeID}}">{{Name}}</option>
                {{/Sizes}}
            </select>
        </td>
    </tr>
    {{/Products}}
</table>

How can I build the select boxes using the mon colour/size data from the global context, but for each table row set the selected="selected" attribute on the options which have values matching the current product's Colour/Size ID?

As it stands, within the loop there is no access to the Colours or Sizes arrays, so the selects are blank. I've tried using a global helper to explicitly pass them into each product from the global context before rendering, like so:

Handlebars.registerHelper('productloop', function(context, options) {
    var ret = [];

    for(var i=0, j=context.Products.length; i<j; i++) {
        var option = context.Products[i];

        option.Colours = context.Colours;
        option.Sizes = context.Sizes;

        ret.push(options.fn(option));
    }

    return ret.join('');
});

And the HTML:

<table>
    {{#productloop}}
    <tr>
        <td>
            <input type="text" value="{{Name}}">
        </td>
        <td>
            <select>
                {{#Colours}}
                <option value="{{ColourID}}">{{Name}}</option>
                {{/Colours}}
            </select>
        </td>
        <td>
            <select>
                {{#Sizes}}
                <option value="{{SizeID}}">{{Name}}</option>
                {{/Sizes}}
            </select>
        </td>
    </tr>
    {{/productloop}}
</table>

Which does work, but it seems very clunky, and I still have no idea how to set the selected attributes for each product's colour/size select.

Can anyone help me out? I have control over the code which generates the JSON, so the JSON structure can be changed if required.

Share Improve this question edited Aug 29, 2013 at 11:37 Mark Bell asked Aug 29, 2013 at 11:30 Mark BellMark Bell 29.8k26 gold badges121 silver badges150 bronze badges 2
  • Why doesn't your JSON have double quotes around the property names? – Qantas 94 Heavy Commented Aug 29, 2013 at 11:34
  • 1 Because it was formatted that way by a Chrome extension I use and I just copied and pasted it in. Fixed now. – Mark Bell Commented Aug 29, 2013 at 11:38
Add a ment  | 

2 Answers 2

Reset to default 5

You can use ../ to step up one level in the namespace:

<select>
    {{#each ../Colours}}
    <option value="{{ColourID}}">{{Name}}</option>
    {{/each}}
</select>

I also switched to {{#each}} as I find it more readable when dealing with ../.

Demo: http://jsfiddle/ambiguous/pFpS4/

Add selected property in your handlebar template for the current product . Eg. for Blue, Small, Red medium...

{
    Colours: [
        { "ColourID": 1, "Name": "Red" },
        { "ColourID": 2, "Name": "Yellow" },
        { "ColourID": 3, "Name": "Blue", "selected" : "selected"  }
    ],
    Sizes: [
        { "SizeID": 1, "Name": "Small" , "selected" : "selected" },
        { "SizeID": 2, "Name": "Medium" },
        { "SizeID": 3, "Name": "Large" }
    ],
    Products: [
        { "ColourID": 1, "SizeID": 1, "Name": "Red Small" },
        { "ColourID": 1, "SizeID": 2, "Name": "Red Medium", "selected" : "selected" },
        { "ColourID": 1, "SizeID": 3, "Name": "Red Large" },
        // and so on...
    ]
}

And then use that inside your template like following.

<table>
    {{#Products}}
    <tr>
        <td>
            <input type="text" value="{{Name}}">
        </td>
        <td>
            <select>
                {{#Colours}}
                <option value="{{ColourID}}" {{selected}}>{{Name}}</option>
                {{/Colours}}
            </select>
        </td>
        <td>
            <select>
                {{#Sizes}}
                <option value="{{SizeID}}"  {{selected}}>{{Name}}</option>
                {{/Sizes}}
            </select>
        </td>
    </tr>
    {{/Products}}
</table>

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论