Jack The Baker
Jack The Baker

Reputation: 1883

ObservableArray to Select Option in KnockOut JS

I want to turn array to select option via knockout js, I know 3 methods for this case, but none of these work perfectly with what I really want, what I want is:

  1. Set default option Choose an option
  2. get selected value
  3. set attr for options

Each method has own issue, but last method has default option and can get selected value, but can't set attr, any idea?

Method 1:

Error:

Uncaught Error: The binding 'value' cannot be used with virtual elements

Status: not working

function myfunc() {
  var self = this;
  self.estimate = ko.observableArray([]);
  self.selectedValue = ko.observable();
  
  var obj = [{
      method_title: "blah blah",
      price: "1000"
    },
    {
      method_title: "blah blah 2",
      price: "2000"
    }
  ];
  self.estimate(obj);
  self.selectedValue.subscribe(function(value) {
    alert(value);
  });
}

ko.applyBindings(new myfunc());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<select id="method">
  <option value="0">Choose an option</option>
  <!-- ko foreach: estimate, value: selectedValue -->
  <option data-bind="text: method_title,
                       attr: { 'data-price': price, 'value': method_title },
                       text: method_title"></option>
  <!-- /ko -->
</select>

Method 2:

Status: working but I could not add default option, it looped everytime.

function myfunc() {
  var self = this;
  self.estimate = ko.observableArray([]);
  self.selectedValue = ko.observable();
  
  var obj = [{
      method_title: "blah blah",
      price: "1000"
    },
    {
      method_title: "blah blah 2",
      price: "2000"
    }
  ];
  self.estimate(obj);
  self.selectedValue.subscribe(function(value) {
    alert(value);
  });
}

ko.applyBindings(new myfunc());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
        <select id="method" data-bind="foreach: estimate,value: selectedValue">
        <option value="0">Choose an option</option>
            <option data-bind="text: method_title,attr: {'data-price':  price, value: method_title}"></option>
        </select>

Method 3:

Status: working but I could not set attr

function myfunc() {
  var self = this;
  self.estimate = ko.observableArray([]);
  self.selectedValue = ko.observable();

  var obj = [{
      method_title: "blah blah",
      price: "1000"
    },
    {
      method_title: "blah blah 2",
      price: "2000"
    }
  ];
  self.estimate(obj);
  self.selectedValue.subscribe(function(value) {
    alert(value);
  });
}

ko.applyBindings(new myfunc());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<select id="method" data-bind="value: selectedValue,options: estimate,
                       optionsText: 'method_title',
                       optionsValue: 'method_title',
                       optionsCaption: 'Choose an option'"></select>

Upvotes: 0

Views: 1595

Answers (2)

Ray
Ray

Reputation: 3959

Your first method had the most promise and so I have corrected that. You don't need to use the value binding in the foreach loop. It has to be used in the <select>, and it works fine.

function myfunc() {
  var self = this;
  self.estimate = ko.observableArray([]);
  self.selectedValue = ko.observable();
  
  var obj = [{
      method_title: "blah blah",
      price: "1000"
    },
    {
      method_title: "blah blah 2",
      price: "2000"
    }
  ];
  self.estimate(obj);
  self.selectedValue.subscribe(function(value) {
    console.log(value);
  });
}

ko.applyBindings(new myfunc());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<select id="method" data-bind="value: selectedValue">
  <option value="0">Choose an option</option>
  <!-- ko foreach: estimate -->
  <option data-bind="text: method_title,
                       attr: { 'data-price': price, 'value': method_title }"></option>
  <!-- /ko -->
</select>

Upvotes: 1

Faizan
Faizan

Reputation: 96

You just need a little bit modification with your 3rd method.

From knockout official documentation Knockout: The "options" binding you can use optionsAfterRender Parameter. I have modified your code. See if it helps

function myfunc() {
  var self = this;
  self.estimate = ko.observableArray([]);
  self.selectedValue = ko.observable();

  var obj = [{
      method_title: "blah blah",
      price: "1000",
      href: "href 1",
      title: "go to href 1"
    },
    {
      method_title: "blah blah 2",
      price: "2000",
      href: "href 2",
      title: "go to href 2"
    }
  ];
  self.setOptionAttr = function(option, item) {           
       if(item)
       {
       ko.applyBindingsToNode(option, {attr: {href:item.href,title:item.title}}, item);
       }            
    }
  self.estimate(obj);
  self.selectedValue.subscribe(function(value) {
    alert(value);
  });
}

ko.applyBindings(new myfunc());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<select id="method" data-bind="value: selectedValue,options: estimate,
                       optionsText: 'method_title',
                       optionsValue: 'method_title',
                       optionsCaption: 'Choose an option',
                       optionsAfterRender: setOptionAttr"></select>

Upvotes: 1

Related Questions