4
votes

I have a Bootstrap modal, and every time it shows up I will use KO to bind a <select> dropdown.

HTML:

<select id="album" name="album" class="form-control" data-bind="options: availableAlbums">
</select>

JavaScript:

$('#uploadModal').on('show.bs.modal', (function () {
        function AlbumsListViewModel() {
            var self = this;
            self.availableAlbums = ko.observableArray([]);

            $.ajax({
                url: "../../api/eventapi/getalbums",
                type: "get",
                contentType: "application/json",
                async: false,
                success: function (data) {
                    var array = [];
                    $.each(data, function (index, value) {
                        array.push(value.Title);
                    });
                    self.availableAlbums(array);
                }
            });
        }

        ko.applyBindings(new AlbumsListViewModel());
    }));

However, on the second showing, KO will present me with this error:

Error: You cannot apply bindings multiple times to the same element.

1

1 Answers

5
votes

The error message says most of it. You have two options:

  1. Call the applyBindings function once, when your page loads. KO will automatically update the View when you update the model in a AJAX success function.
  2. Call the applyBIndings function on each AJAX success, but supply additional parameters to tell it what element to bind to.

Most likely the first option is what you're looking for. Remove the call from the $('#uploadModal').on call and place it on document load (if you haven't already).

To see what I mean, here's two fiddles:

  1. Your current code with the error you mention.
  2. Refactored version that doesn't have the error.

The latter tries to stay as close as possible to your initial version (so as to focus on the problem at hand), and goes along these lines:

function AlbumsListViewModel() {
    var self = this;
    self.availableAlbums = ko.observableArray([]);
}

var mainViewModel = new AlbumsListViewModel();
ko.applyBindings(mainViewModel);

$('#uploadModal').on('show.bs.modal', (function () {
    // Commenting things out to mock the ajax request (synchronously)
    var data = [{Title:'test'}];
    /*$.ajax({
        url: "../../api/eventapi/getalbums",
        type: "get",
        contentType: "application/json",
        async: false,
        success: function (data) {*/
            mainViewModel.availableAlbums.removeAll();
            var array = [];
            $.each(data, function (index, value) {
                array.push(value.Title);
            });
            mainViewModel.availableAlbums(array);
        /*}
    });*/
}));