Search code examples
knockout.jsknockout-components

How to reuse a knockout component


I've recently been playing around with a yeoman knockout template and I've been trying to make a simple email site. I've managed to retrieve my email's via a json request. But what I would like to do now is show the contents of the email in a accordion drop down under the table row that shows the basic email information. I have a knockout component for my email and I have built another for my email details. I do not want to load the email detail component until a button click, and then populate the email detail template as it expands.

So far I have got to the point of expanding the accordion but I am at a bit of a loss how to populate the email detail components. I would do this with a ajax call to return the email detail JSON from the msg_id value.

Any Help would be great.

My email page looks like so

Action Items

<table class="table table-condensed" style="border-collapse:collapse;">
    <thead>
        <tr data-bind="foreach: Headers">
            <th>
                <b>
                    <a href="#" data-bind="click: $parent.sort, text: title"></a>
                </b>
            </th>
        </tr>
    </thead>
    <tbody data-bind="foreach: Messages">
        <tr>
            <td>
                <button class="btn btn-success btn-6 btn-6g" data-bind="text: msg_id, click: toggleDetail"></button>
            </td>
            <td data-bind="text: subject"></td>
            <td data-bind="text: sender_addr"></td>
            <td data-bind="date: created"></td>
            <td></td>
        </tr>
        <tr class="Details Hidden">
            <td colspan="5">
                <div>
                    <!--click tot populate this component below-->

                 <emaildetail data-bind="attr: { id: msg_id}"></emaildetail> 
                </div>
            </td>
        </tr>
    </tbody>
</table>

my code behind for the button event

  this.toggleDetail = function (data, e) {
        var clickedButton = $(e.target);
        var parentRow = clickedButton.parents("tr");
        var res = parentRow.next().toggleClass("Hidden");

        // This is what I want to pass to my email detail component

        var id = data.msg_id;
        // component.emaildetail.refresh(id);
    };

I'm not really sure how to bind and fill the relevant component?


Solution

  • You've got to start thinking in a different way... in knockout, your javascript manipulates the model/viewmodel ONLY. It should not do any DOM stuff or otherwise interact with the view/page..

    <table class="table table-condensed" style="border-collapse:collapse;">
        <thead>
            <tr data-bind="foreach: Headers">
                <th>
                    <b>
                        <a href="#" data-bind="click: $parent.sort, text: title"></a>
                    </b>
                </th>
            </tr>
        </thead>
        <tbody data-bind="foreach: Messages">
            <tr>
                <td>
                    <button class="btn btn-success btn-6 btn-6g" data-bind="text: msg_id, click: toggleDetail"></button>
                </td>
                <td data-bind="text: subject"></td>
                <td data-bind="text: sender_addr"></td>
                <td data-bind="date: created"></td>
                <td></td>
            </tr>
            <tr class="Details Hidden" data-bind="visible: msgVisible">
                <td colspan="5">
                    <div>
                        <!--click tot populate this component below-->
    
                     <emaildetail data-bind="attr: { id: msg_id}"></emaildetail> 
                    </div>
                </td>
            </tr>
        </tbody>
    </table>
    

    Each message should be a class with all the properties (subject, sender_addr, etc), a msgVisible observable boolean, and a toggleDetail method that just does this:

    this.toggleDetail = function () {
        this.msgVisible(!this.msgVisible);
        };
    

    Here's a fiddle example: http://jsfiddle.net/brettwgreen/92qnvnaw/