0
votes

I am struggling figuring out how to correctly add more options to a select list dynamically.

This code works, but it wipes out everything existing in the array because it is setting the value of the array instead of pushing:

// add seller to dropdown list
var opts = [];
opts.push({Text: studentName, Value: result.sellerID});
console.log("opts: " + JSON.stringify(opts));
if (sellerOptionModel.sellers.indexOf(opts) < 0) {
  sellerOptionModel.sellers(opts);
}

And this code does not work, it just adds a blank item to the dropdown select list:

// add seller to dropdown list
var opts = [];
opts.push({Text: studentName, Value: result.sellerID});
console.log("opts: " + JSON.stringify(opts));
if (sellerOptionModel.sellers.indexOf(opts) < 0) {
  sellerOptionModel.sellers.push(opts);
}

ViewModel:

var SellerOptionModel = function() {
  var self = this;
  self.sellers = ko.observableArray([]);
  self.sellerID = ko.observable();
}

Full JS function with the above KO code in in the success part:

$("#nextForm").on('click', function(e) {
  e.preventDefault();
  var room = $("#roomSelect").val();
  var invalidItems = invalidItemsArr.join(",");
  $("#invalidItems").val(invalidItems);
  if(verify == "True") {
    var seller = $('#sellerSelect').val();
  }
  if(room == "") {
    e.preventDefault();
    slideDownMsg("Please select a room first.");
    slideUpMsg(4000);
  } else {
    var firstName = capitalizeFirstLetter($.trim($("#firstName").val()));
    var lastName = capitalizeFirstLetter($.trim($("#lastName").val()));
    if(verify != "True" && (firstName == "" || lastName == "")) {
      e.preventDefault();
      slideDownMsg("Please fill in the student's first and last name.");
      slideUpMsg(3500);
    } else if(seller == "") {
      e.preventDefault();
      slideDownMsg("Please select a seller from the dropdown.");
      slideUpMsg(3500);
    } else { // all good we can save the student
      $.ajax({
        url: '@Url.Action("SaveStudent", "Tally")',
        type: 'POST',
        data: $("#tallyForm").serialize(),
        success: function (result) {
          if(result.success == true) {
            var studentName = firstName + " " + lastName;
            slideDownMsg("Tally entry saved for " + studentName + ".");
            slideUpMsg(4000);
            var room = $("#roomSelect").val();
            $("#tallyForm")[0].reset();
            $("#roomSelect").val(room);
            tallyViewModel.items([]);
            tallyViewModel.addLine();
            if(room != "") {
              getImage(room);
            }
            tallyViewModel.runningQty(0);
            tallyViewModel.runningTotal(0);

            // add seller to dropdown list
            var opts = [];
            opts.push({Text: studentName, Value: result.sellerID});
            console.log("opts: " + JSON.stringify(opts));
            if (sellerOptionModel.sellers.indexOf(opts) < 0) {
              sellerOptionModel.sellers.push({Text: studentName, Value: result.sellerID})
            }
            sellerOptionModel.sellers.sort();
          } else {
            slideDownMsg("Failed saving tally entry for " + firstName + " " + lastName + ".");
            slideUpMsg(4000);
          }
        },
        error: function (request, status, error) {
          e.preventDefault();
          displayError("Error", request.responseText);
        }
      });
    }
  }
});
1
You're adding the opts array to your sellers array (array within an array). You likely want sellerOptionModel.sellers.push({Text: studentName, Value: result.sellerID}) instead. But your indexOf will always be -1 as that compares objects by reference. - JohnnyHK
Aw, so how can I only add if the item does not exist? - dmikester1
"indexOf(opts)" is never going to work because opts is a new array that you just created. There's no circumstance in which it would already exist in the array. I can throw together an example if you show more of your code - Jason Spake
That would be great. I have a lot of code on the page but I think the rest does not relate to this. What else do you need to see? - dmikester1
Basically, every time I click a button that code will get called adding the current seller to the array(dropdown). And I only want unique sellers in the dropdown. - dmikester1

1 Answers

2
votes

Dynamically adding items to a select list in knockout should be as easy as adding the item to the observable array that the select list is bound to. The trick is not replacing the contents of the existing array.

Instead of creating a new array, and setting the observable array to it, you should directly push the item into the original observable array.

sellerOptionModel.sellers.push({Text: studentName, Value: result.sellerID});

The problem of only adding an item if it doesn't already exist boils down to how you define whether an item is the same item. Normally an "object" is only equivalent if it's the exact same object reference, and a similar object with the same internal values does not count. For example:

var a = { id: 3 };
var b = { id: 3 };
console.log(a == b); //returns false;

What you really want to use to compare your option objects is probably the Value property that you've given them. indexOf isn't going to help you there so you'll need to loop through the items manually and check each one's Value property against the new item's value.

var match = false;
for (var i = 0; i < sellerOptionModel.sellers().length; i++) {
    if(sellerOptionModel.sellers()[i].Value == result.sellerID){
        match = true;
        break;
    }
}
if (!match) {
    console.log("new id added");
    sellerOptionModel.sellers.push({Text: studentName, Value: result.sellerID});
    sellerOptionModel.sellers.sort();
}else{
    console.log("id already exists")
}

Working example: https://jsfiddle.net/jlspake/8c3tvn9u/