0

I have a UI containing tabs and each tab gets its caption populated from a jquery ajax call. I have a text box (and a few other controls including a dropdown list) that the user fills out or selects an item. I need to maintain state for each tab so that when the user selects a tab, the control values get updated at the same time. So this is essentially an array with one array item for each tab.

In the case of a textbox, the data is simply the text the user entered. In the case of a dropdown, it is the selected item in the list. The dropdown data is the same for each tab. The tab control is really a tab strip so there is one text box for all the tabs and one dropdown, etc.

My question is whether knockout is the right tool for this? And if so, how is this accomplished. I've used knockout.js before but for more trivial things.

1 Answer 1

1

Knockout has a nice feature is called computed function here which in fact it is a function that is dependent on other observables in your model, and will automatically update whenever any of these dependencies change. So in your case whenever you change the state observable, since you already are using it inside computed function, your computed function automatically will be triggered and then based on your state or any other observable you send a request using Ajax and in success you update your model.

Below is a simple example of how to approach this:

Example: https://jsfiddle.net/kyr6w2x3/156/

HTML:

<select data-bind="value:State">
  <option value="1"> state 1</option>
  <option value="2"> state 2</option>
  <option value="3"> state 3</option>
</select>
<ul data-bind="foreach:MyArray">
  <li> 
    <span data-bind="text:Name"></span>
  </li>
</ul>

VM:

var data1 = [{ Id: 1, Name: "Name 1" },{ Id: 2, Name: "Name 2" },{ Id: 3, Name: "Name 3" } ];
var data2 = [{ Id: 10, Name: "Name 10" },{ Id: 20, Name: "Name 20" },{ Id: 30, Name: "Name 30" } ];
var data3 = [{ Id: 100, Name: "Name 100" },{ Id: 200, Name: "Name 200" },{ Id: 300, Name: "Name 300" } ];
var data = [];

function MainViewModel(){
   var self = this;
   self.MyArray = ko.observableArray([]);
   self.State  = ko.observable(1)

    self.LoadTab = ko.computed(function() {
        switch(self.State()){
        case "1":
            data = data1;
            break;
        case "2":
            data = data2;
            break;
        case "3":
            data = data3;
            break;
        }
        //Call your ajax based on state here and update your array in ajax's success.
         self.MyArray($.map(data, function (item) {
           return new ItemViewModel(item);
         }));

    }, self);

}

function ItemViewModel (data){
  var self = this;
  self.Id = ko.observable(data.Id);
  self.Name = ko.observable(data.Name);
}

var viewModel = new MainViewModel();
ko.applyBindings(viewModel);
Sign up to request clarification or add additional context in comments.

1 Comment

I'd suggest making MyArray the computed property, which only requires you to make the computed return the result of the map operation. Currently, it isn't returning anything, which makes LoadTab() always undefined. Since it only references State, you could also replace it with a self.State.subscribe() that sets MyArray. (Note that you can also use a computed as a 'subscription`, without storing a reference).

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.