Puzzle84
Puzzle84

Reputation: 540

KnockoutJS + Chosen are resetting my observable value after i set it

So i'm building this chart building ui. were you can pick fields from a database to build a graph. and the graphs have a refresh interval dropdown.

all works well until i'm trying to load a value from a saved "view" the value gets set as i can see when i add a subscribe to the RefreshInterval variable.

but it instantly get's reset to the 0'd index of my options array.

Console.log output of subscribe to RefreshInterval

[html]

<div class="wrapper wrapper-content" id="charts">
  <select id="interval" data-bind="options: RefreshIntervals,
    optionsText: 'Value',
    value: RefreshInterval,
    chosen: {
      disable_search_threshold: 0,
      width:'175px',
      no_results_text: 'No results!',
      placeholder_text_single: 'Select an interval',
      search_contains: true,
    }">
  </select>
</div>

[javascript]

function ViewModel() {
    var self = this;
    this.RefreshIntervals = ko.observableArray([
                new Interval(0, "Never"), new Interval(10, "seconds"), new Interval(1, "minutes"), new Interval(5, "minutes")
            ]);
    this.RefreshInterval = ko.observable(new Interval(5, "minutes"));
};

var Interval = (function () {
    function Interval(length, measurement) {
    var _this = this;
    this.Length = 0;
    this.Measurement = "";
    this.Value = "";
    this.TimeoutValue = 0;
    this.GetTimeoutValue = function () {
      switch (_this.Measurement) {
        case "seconds":
          return _this.Length * 1000;
        case "minutes":
          return _this.Length * 60000;
        default:
          return 0;
      }
    };
    this.Length = length;
    this.Measurement = measurement;
    if (length == 0 || measurement == "Never") {
      this.Value = "Never";
    }
    else {
      this.Value = this.Length + " " + this.Measurement;
    }
    this.TimeoutValue = this.GetTimeoutValue();
  }
  return Interval;
}());

ko.bindingHandlers.chosen =
{
    init: function (element, valueAccessor, allBindings) {
      $(element).chosen(valueAccessor());

      // trigger chosen:updated event when the bound value or options changes

      $.each('value|selectedOptions|options'.split("|"), function (i, e) {
          var bv = allBindings.get(e);
          if (ko.isObservable(bv)) {
            bv.subscribe(function () {
              $(element).trigger('chosen:updated');
            });
          }
      });
    }
};
var vm = new ViewModel();
ko.applyBindings(vm, document.getElementById("charts"));

i have a fiddle here: Fiddle

I have 3 of these dropdown boxes that need to be populated. I want the value to be the actual element and not a value field which i then need to go co-relate to the actual object in the options list as the options list might change.

Any clue how i can solve this?

Upvotes: 1

Views: 81

Answers (1)

williamsandonz
williamsandonz

Reputation: 16430

The value attribute on the <select> wasn't being generated properly, you need to add optionsValue: 'Value' to your binding

Basically there is a limitation in Knockout that you can't bind a selected value to the wrapping object.

Because of this restriction the only way to programatiicaly set the option you want is:

vm.RefreshInterval("10 seconds");

The computed will of course return the string value rather than the entire object. Then you can simply do this to get the object. (Or use underscore or lodash to make the code look a bit more elegant)

this.RefreshInterval.subscribe(function(newValue){
 var obj = null;
 for(var i=0; i<self.RefreshIntervals().length; i++) {
   var interval = self.RefreshIntervals()[i];
   if(interval.Value === newValue) {
     obj = interval;
     break;
   }
 }
 console.log(obj);
); 

Note you'll also need optionsValue: 'Value',

Updated working fiddle

Upvotes: 1

Related Questions