2

Searched all over stackoverflow & other sources - can't seem to find anything of much help.

I have a statistical table-like UI with data driven content. The data is a huge array/object serialised on the back-end.

I am then extracting the values within that array - which are set as observables - and outputting them on the page with data-bind attributes.

The table displays the top performing artist in a given category and the two related artists below.

The problem is that we need to dynamically change the data-bind attribute so that it is capable of looking at a variable property in the data.

For example, if the user filters by "Artist", we want to display the Artist's Name (i.e

<span data-bind="text: ArtistName()"></span>

BUT

if the user filters by "Genre", we want the same part of the HTML to be able to display the Track Length (or any other arbitrary observable property) (i.e )

Ultimately, I want to have a variable data-bind attribute, like

I know that I can achieve this using a potentially huge if statement, like so:

<!-- ko if: $parent.SortMethod() == 'Topic1' -->
<span data-bind="text: Topic1()"></span>
<!-- /ko -->
<!-- ko if: $parent.SortMethod() == 'Topic2' -->
<span data-bind="text: Topic2()"></span>
<!-- /ko -->
<!-- ko if: $parent.SortMethod() == 'Topic3' -->
<span data-bind="text: Topic3()"></span>
<!-- /ko -->

...etc

Surely there is a more efficient way...?

1
  • Sharing how you are extracting and outputting them would help. Commented Jun 4, 2014 at 21:42

1 Answer 1

2

You'll have to bind the grid data to a function that will then return the data sorted / filtered by the desired field. Also, you'll have to bind that drop-down list to an observable in your view-model.

function GridModel(data)
{
      var self = this;
      self.RawData = data;
      self.SortedBy = ko.observable();

      self.GetGridData = function()
      {
           var ret = self.RawData();
           var sortingFld = self.SortedBy();

           if (sortingFld)
           {
               ret = ret.sort(function (a, b) {
                   a = ko.unwrap(a[sortingFld]);
                   b = ko.unwrap(b[sortingFld]);

                   return (a == b ? 0 : a < b ? -1 : 1) * 1;
                   });
           }

           return ret;
      }
}

HTML:

<table class="grid">
    <thead>
        <th>Category</th>
        <th>Artist</th>
        <th>Track</th>
    </thead>

    <tbody data-bind="foreach: GetGridData()">
        <td data-bind="text: Category"></td>
        <td data-bind="text: Artist"></td>
        <td data-bind="text: Track"></td>
    </tbody>
</table>

The drop-down will then be able to change the SortedBy observable and automatically refresh the grid accordingly:

<select data-bind="value: SortedBy, options: ['Artist', 'Track']"></select>

(The code above only demonstrates ascending sorting, but you can easily expand it for filtering as well).

Sign up to request clarification or add additional context in comments.

4 Comments

Shouldn't GetGridData be a ko.computed, otherwise what will trigger a recalculation when SortedBy changes
@RobertSlaney, Knockout is detecting the dependency of GetGridData on SortedBy automatically. Also, computed will cause Knockout to serialize the return value of the function upon calling ko.toJSON which is not what we want.
Thanks you for the answer - My initial explanation didnt reflect the problem accurately. Updated question with more details.
It doesn't need to be a computed because the dependencies are set on the binding which is a computed in itself. Although I still would have placed it in a ko.computed(). I also don't see a call to ko.toJSON anywhere.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.