0
votes

I'm new to knockout.js for data binding. I have a simple example below using knockout.js to data bind a table, but when it comes to data binding nested tables with filter is hard for me to figure it out in knockout.js. If you look at the two sample tables below, one is using knockout.js to data bind a record in one table and the other one is a nested table using Razor codes with Where clause in the foreach statement to filter the replies of each comments. The second one with Razor codes is a nested table I used to display and databind comments and its replies. I'm trying to apply this in knockout.js for data binding. How do I do this in knockout.js? Thanks...

Table 1.

<table id="products1" data-bind="visible: Products().length > 0">
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Category</th>
                <th>Price</th>
                <th>Actions</th>
            </tr>
        </thead>
        <tbody data-bind="foreach: Products">
            <tr>
                <td data-bind="text: Id"></td>
                <td data-bind="text: Name"></td>
                <td data-bind="text: Category"></td>
                <td data-bind="text: formatCurrency(Price)"></td>

                <td>

                    <button data-bind="click: $root.edit">Edit</button>
                    <button data-bind="click: $root.delete">Delete</button>

                </td>

            </tr>
        </tbody>
        <tfoot>
            <tr>
                <td></td>
                <td></td>
                <td>Total :</td>
                <td data-bind="text: formatCurrency($root.Total())"></td>
                <td></td>
            </tr>
        </tfoot>
    </table>

Table 2.

<table id="mytable">  

  @foreach (var item in Model.Comments)
  {
    <tr >
        <td class="tdstyle" >

  <div style="font-weight:bold;">  @Html.DisplayFor(modelItem => item.name) </div> 

   <p class="comment more" style ="white-space: pre-line; margin-top:0px;margin-bottom:0px; border-radius: 4px 4px 4px 4px; max-width :500px; min-height :5px;  display :block; background-color: #CCCCFF">  @Html.DisplayFor(modelItem => item.comment) </p>
  <p style="margin-top:2px;margin-bottom:0px;height:3px"> <input type="button" id="like" name="like" value="Like" style="color:blue;border:0px;background-color:inherit;cursor:pointer" /> <input type="button" class ="Reply" name="Reply" value="Replie(s)"  style="margin-bottom:0px;color:blue;border:0px;background-color:inherit;cursor:pointer" /></p>                                                                    
   <div id="divReply" class ="divrep" style=" position:relative;left:50px; overflow:auto;margin-top:0px;margin-bottom:0px">
       <table>
           @foreach (var item2 in Model.Replies.Where(r => r.idrep == item.Id))
           {
                 <tr >

                     <td >
                         <div style="font-weight:bold;"> @Html.DisplayFor(modelItem => item2.namerep) </div> 

                     <p class="comment more" style ="margin-top:0px;margin-bottom:0px;white-space:pre-line; border-radius: 4px 4px 4px 4px; max-width :445px; min-height :5px;  display :block; background-color: #CCCCFF;">@Html.DisplayFor(modelItem => item2.reply)  </p>

                   </td>
                 </tr>
           } 
       </table> 

        </td>       
    </tr>

  }

</table>
1
simple you just need to place ` Model.Comments` & Model.Replies data into separate observable-arrays . later inner foreach should have conditional data based on Id . cheers - super cool
@supercool If you have any sample articles or tutorials demonstrating similar to what you said. Can you give me so I can study them. Thanks - timmack
ok i will try to set you a fiddle soon . - super cool
Thanks, I'm looking forward to that...cheers - timmack
@supercool Thanks for this fiddle. It seems like everything is fine. Pls post it as answer and never delete this fiddle link cause I have to study them. Thanks again - timmack

1 Answers

2
votes

Try something like this & use computed which will be apt for this situation .

View:

<div class='liveExample' data-bind="foreach:comments"> <b data-bind="text:name"> </b>
    <br/>
    <div data-bind="foreach:array"> <span data-bind="text:nameRep"></span>
 <span data-bind="text:reply"></span>
        <br/>
    </div>
    <hr/>
</div>

viewModel:

var data = [{
    'name': 'charlie',
    'id': 1
}, {
    'name': 'mack',
    'id': 2
}, {
    'name': 'dargen',
    'id': 3
}, {
    'name': 'cool',
    'id': 4
}, {
    'name': 'silver',
    'id': 5
}]


var ViewModel = function () {
    var self = this;
    self.innerLoop = ko.observableArray();
    self.replies = ko.observableArray([{
        'nameRep': 'becok',
        'rid': 1,
        'reply': 'hello'
    }, {
        'nameRep': 'saluk',
        'rid': 1,
        'reply': 'hey bro'
    }, {
        'nameRep': 'chin-ui',
        'rid': 4,
        'reply': 'wassup'
    }, {
        'nameRep': 'mark',
        'rid': 3,
        'reply': 'chill out'
    }, {
        'nameRep': 'kaj',
        'rid': 3,
        'reply': 'ok dear'
    }, ]);

    var comment = function (c) {
        this.id = ko.observable(c.id);
        this.name = ko.observable(c.name);
        this.array = ko.computed(function () {
            var name = this.id();
            var arr = [];
            arr = ko.utils.arrayFilter(self.replies(), function (item) {
                return item.rid === name;
            });
            return arr;
        }, this);
    }

    self.comments = ko.observableArray();
    ko.utils.arrayForEach(data, function (item) {
        self.comments.push(new comment(item));
    });
};

ko.applyBindings(new ViewModel());

Check the working fiddle here