Search code examples
javascriptjqueryasp.net-mvc-4knockout.jsrazor-2

How to filter table through checkbox values


In my Razor view I have a table with 3 non displayed properties. Id_Loaction, Id_Level & Id_Section

Above this table I have 3 lists of checkboxes for every location, level & section with the appropriate Ids as the value.

@foreach (var section in Model.Sections)
{
    <li>
      <input type="checkbox" data-bind="checked: data" value="@Html.Encode(section.Value)"/>@Html.Encode(section.Text)
    </li>
}   

Note: section.Value is the ID of the element which is also used in the table rows

The table itself is fairly simple built:

@foreach (var item in Model.Offers) 
{
    <tr data-bind="visible: data.IsChecked == true ">
    <td>
        @Html.DisplayFor(modelItem => item.Description)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Location)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Section.Text)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Section.Value)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Section.IsChecked)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Level)
    </td>
    <td>
        @Html.ActionLink("Details", "Details", new { id=item.ID })
    </td>
</tr>
}


<script type="text/javascript">
    var data = @Html.Raw(Json.Encode(Model.Sections));

    function FormViewModel(data) {
        this.data = ko.observableArray(data);
    }

    window.viewModel = new FormViewModel(data);

    console.log(viewModel.data());    
    ko.applyBindings(viewModel);
</script>

/edit: I have updated the code to my actual mess. The Model.Sections is a ViewModel, which is identical to the ViewModel used for Model.Offers.Section. Both contain a Value, Text and IsChecked property.

How can I compare both those and display only the table rows on which the section is checked?

Please go slow on me. Kind regards


Solution

  • this is an attempt at using knockout with a trimmed down version of what i am assuming Serv is trying to do. This is an example of a simple filter on a list of objects and can easily be expanded to include more filters and more complex models.

    Fiddle http://jsfiddle.net/zTRq2/3/

    Simple Filter ViewModel:

    function filterViewModel(data) {
        var self = this;
        self.text = ko.observable(data.text);
        self.checked = ko.observable(data.checked);
    }
    

    Trimmed down Offer View Model:

    function offerViewModel(offer) {
        var self = this;
        self.description = offer.description;
        self.location = offer.location;
    }
    

    Main View Model:

    function FormViewModel(data) {
        var self = this;
        // map data from server to locations filter
        self.locations = ko.observableArray(ko.utils.arrayMap(data.locations, function (filter) {
            return new filterViewModel(filter);
        }));
    
        self.offersView = ko.computed(function () {
            // get list of offers that were passed in, we'll manipulate filteredOffers from now on
            var filteredOffers = data.offers;
    
            // get all selected locations view models
            var selectedFilterLocations = ko.utils.arrayFilter(self.locations(), function (location) {
                return location.checked();
            });
    
            // run through util function to filter only offers that match any selected location
            filteredOffers = ko.utils.arrayFilter(filteredOffers, function (offer) {
                var matchesLocation = false;
                ko.utils.arrayForEach(selectedFilterLocations, function (location) {
                    if (offer.location === location.text()) matchesLocation = true;
                });
                return matchesLocation;
            });
    
            return filteredOffers;
        });
    };
    

    HTML:

    <!-- list of location checkboxes -->
    <ul class="unstyled inline" data-bind="foreach: locations">
        <li>
            <input type="checkbox" data-bind="checked: checked" /> <span data-bind="text: text"></span>
    
        </li>
    </ul>
    
    <!-- table which is bound to the offersView computed observable -->
    <!-- offersView is recalculated everytime a selection changes from the filter list -->
    <table class="table-bordered">
        <tbody data-bind="foreach: offersView">
            <tr>
                <td data-bind="text: description"></td>
                <td data-bind="text: location"></td>
            </tr>
        </tbody>
    </table>