Pushing array to select in knockout gives just one option

Viewed 31

I am using MVC and a Razor View I'm trying to bound data received from a controller to a select using a knockout model, If I try to push directly the dynamic array I get only one option like this one

Only one option select:

Only one option select

I'm sure that I'm missing something stupid, I have already tried to return a new SelectList and using optionsText and optionsValue but didn't do the work. I'm sure the knockout model is correct because if I write

viewModel.dliveryDates.push("option1","option2");

it works as expected

Here's my controller code that reads some data from database and send it back to the view

[HttpPost]
public JsonResult GetDeliveryDates(string code)
{
    OrderHeaderPageModel instance = ObjectFactory.Create<OrderHeaderPageModel>();
    instance.DeliveryDateRanges = PopulateDeliveryDateRanges(code);
    return Json(instance.DeliveryDateRanges.ToArray());
}

Here's is my View code

@Html.DropDownList("deliveryranges", new SelectList(string.Empty, "Code", "Description"), "- Seleziona -", new { @data_bind = "options:dliveryDates" })

And finally my knockout model

function OrderHeaderViewModel() {
    var self = this;
    self.save = function () {
        return true;
    }
    self.dliveryDates = ko.observableArray([]);
}

var viewModel = new OrderHeaderViewModel();
ko.applyBindings(viewModel, el);

$("#ordertypes").change(function () {
    var postUrl = "/checkout/getdeliverydates";
    $("#deliveryranges").empty();
    $.post(postUrl,
        {
            code: $("#ordertypes").val(),
            __RequestVerificationToken: Sana.Utils.getAntiForgeryToken()
        }, function (data) {
            var arry = [];
            var array = $.map(data, function (value, index) {
                return [value];
            });
            $.each(data, function (i, data) {
                arry.push(data.Code);
            });  
            viewModel.dliveryDates.push(arry);
        }
    );
})
1 Answers

It looks like the code is doing some extra work mapping data that is not used in the ajax callback. Hope the following code helps.

function OrderHeaderViewModel() {
  var self = this;
  self.getData = function() {

    //function to simulate filling the array from the server.
    var data = ["Item 1", "Item 2", "Item 3", "Item 4"];
    self.dliveryDates(data);

    var mappedData = data.map(function(item, index) {
      return {
        id: index,
        description: item

      };
    });
    viewModel.mappedDliveryDates(mappedData);

  }
  self.save = function() {
    return true;
  }
  //added to put the selected values in
  self.selectedValue = ko.observable();
  self.selectedMappedValue = ko.observable();

  self.mappedDliveryDates = ko.observableArray([]);
  self.dliveryDates = ko.observableArray([]);

}

var viewModel = new OrderHeaderViewModel();
ko.applyBindings(viewModel);

$("#ordertypes").change(function() {
  var postUrl = "/checkout/getdeliverydates";
  $("#deliveryranges").empty();
  $.post(postUrl, {
    code: $("#ordertypes").val(),
    __RequestVerificationToken: Sana.Utils.getAntiForgeryToken()
  }, function(data) {
    // if the data needs to be transformed and is already an array then you can use
    var mappedData = data.map(function(item, index) {
      return {
        id: index,
        description: item
      };
    });
    // If the data is already in the format that you need then just put it into the observable array;
    viewModel.mappedDliveryDates(mappedData);
    viewModel.dliveryDates(data);
  });
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

Server Data Values -
<select data-bind="options: dliveryDates, value:selectedValue, optionCaption: 'Choose...'"></select>
<br/> Mapped Values -
<select data-bind="options: mappedDliveryDates, optionsText:'description', value: selectedMappedValue, optionCaption: 'Choose...'"></select>
<br/>
<button data-bind="click: getData">Load Data</button>
<br/>
<br/>
<pre data-bind="text: ko.toJSON($root)"></pre>

Related