0

I have a model which contains relationship between Tag and Task. So many TaskIDs can relate to many TagIDs

However, I want to display unique TagIDs and TagNames in a table. So instead of the duplicate rows in the JSFiddle example, it should return distinct rows i.e. only 2 rows in the table.

The second table I have works fine as I am returning just one column.

Below is my code...

var viewModel = function(data) {
    var self = this;
   
    self.tagTaskMappings = ko.observableArray([
    {TagID: 2, TagName: "A", TaskID: 1, TaskName: "ManualItems"},
    {TagID: 2, TagName: "A", TaskID: 2, TaskName: "Trades"},
    {TagID: 3, TagName: "B", TaskID: 1, TaskName: "ManualItems"},
    {TagID: 3, TagName: "B", TaskID: 2, TaskName: "Trades"},
    {TagID: 3, TagName: "B", TaskID: 3, TaskName: "Cash"},
    {TagID: 3, TagName: "B", TaskID: 4, TaskName: "ReportA"}
    ]); 
    
    self.filteredtagMappings = ko.computed(function () {
        var types = ko.utils.arrayMap(self.tagTaskMappings(), function (item) {
            return { TagID: item.TagID, TagName: item.TagName, IsTagActive: item.IsTagActive};
        });        
        return ko.utils.arrayGetDistinctValues(types).sort();
    }, this);
   
    self.filteredtagMappings2 = ko.computed(function () {
        var types = ko.utils.arrayMap(self.tagTaskMappings(), function (item) {
            return item.TagName;
        });        
        return ko.utils.arrayGetDistinctValues(types).sort();
   }, this); 

};

ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.3.0/knockout-min.js"></script>
<table class="table table-hover">
            <thead>
                <tr>
                    <th>Tag ID</th>
                    <th>Tag name</th>
                    <th>Task ID</th>
                    <th>Task name</th>
                </tr>
            </thead>
            <tbody>
                <!-- ko foreach: filteredtagMappings -->
                <tr>
                    <td class="ui-state-default" data-bind="text: TagID"></td>
                    <td class="ui-state-default" data-bind="text: TagName"></td>
                    <td></td>
                </tr>
                <!-- /ko -->
            </tbody>
        </table>

<hr />
 
     <table class="table table-hover">
        <thead>
            <tr>
                <th>Tag ID</th>
                <th>Tag name</th>
                <th>Task ID</th>
                <th>Task name</th>
            </tr>
        </thead>
        <tbody>                
            <!-- ko foreach: filteredtagMappings2 -->
            <tr>
                <td></td>
                <td class="ui-state-default" data-bind="text: $data"></td>
                <td></td>
            </tr>
            <!-- /ko -->                
        </tbody>
    </table>

http://jsfiddle.net/4qc570eo/2/

Kevin
  • 241
  • 6
  • 21

1 Answers1

0

here is a solution using underscorejs and the knockout mapping pluggin.

http://jsfiddle.net/4qc570eo/6/

self.filteredtagMappings2 = function() {
    var returnObject = ko.observableArray('');
    var uniques = _.map(_.groupBy(ko.toJS(self.tagTaskMappings), function(item) {
      return item.TagID;
    }), function(grouped) {
      return grouped[0];
    });
    ko.mapping.fromJS(uniques, {}, returnObject);
    return returnObject;
  };
};
Bryan Dellinger
  • 4,724
  • 7
  • 33
  • 79
  • The above works well in JSFiddle. However, in my Web App in the self.getChildren function, 'row' is set as 'undefined'. Why would this be? – Kevin Jun 14 '17 at 14:31
  • think the problem might be you need to unwrap row. var unwrappedRow = ko.toJS(row); because the ko mapping turned the attributes into observables. here is a fiddle. http://jsfiddle.net/4qc570eo/8/ – Bryan Dellinger Jun 14 '17 at 15:59
  • I tried the updated code but I still get undefined. The data is actually loaded from an API so this might be the issue? How do I ensure self.filteredtagMappings and self.getChildren get called correctly after API is done? – Kevin Jun 19 '17 at 08:15