Niko Gamulin
Niko Gamulin

Reputation: 66565

Unable to bind the selected value from listbox

I tried to create a dual listbox to move items from one to another and then finally pass the data from lists back to controller.

As a javascript newbie I am struggling with data binding. To move the data from one listbox to another, I have created the following form:

 <div class="container">
            <form role="form">
        <div class="container">
            <div class="row">
                <div class="col-md-5">
                    <div class="form-group">
                        <label for="SelectLeft">User Access:</label>
                        <select class="form-control" id="SelectLeft" multiple="multiple" data-bind="options : ownership, optionsText:function(item) { return item.FirstName + ' ' + item.LastName}, value:selectedItem">
                            @*<select class="form-control" id="SelectLeft" multiple="multiple">
                        </select>
                    </div>
                </div>   
                <div class="col-md-2">

                        <div class="btn-group-vertical">
                            <input class="btn btn-primary" id="MoveLeft" type="button" value=" << " data-bind="click: addItem" />
                            <input class="btn btn-primary" id="MoveRight" type="button" value=" >> " data-bind="click: removeSelected" />       
                        </div>

                </div>
                <div class="col-md-5">
                    <div class="form-group">
                        <label for="SelectRight">Owners:</label>
                        <select class="form-control" multiple="multiple" id="SelectRight" data-bind="options : availableOwners, optionsText:function(item) { return item.FirstName + ' ' + item.LastName}, value:selectedItem">
                        </select>
                    </div>
                </div>

            </div>                
        </div>
                <button type="submit" class="btn btn-default" value="Cancel" name="addEditUser" id="btnCancel" data-bind="click: cancel">Cancel</button>
                <button type="submit" class="btn btn-default" value="Submit" name="addEditUser" id="btnSubmit" data-bind="click: submit">Save</button>
    </form>
</div>

<script>
    var data=@(Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model)));
    var owners = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.AccessOwners));
    var availableOwners = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.owners));
    function viewModel() {
        this.username=ko.observable(data.Username);
        this.password=ko.observable(data.Password);
        this.email=ko.observable(data.Email);
        this.isActive=ko.observable(data.IsActive);
        this.userId = ko.observable(data.UserId);
        this.ownership=ko.observable(owners);
        this.availableOwners = ko.observable(availableOwners)
        this.selectedItem = ko.observable();

        this.submit = function()
        {
            $.ajax({
                url: '@Url.Action("UserSave", "Admin")',
                type: 'POST',
                data: ko.toJSON(this),
                contentType: 'application/json',
            });
            window.location.href = url;
            return false;
        }

        this.cancel = function()
        {
            window.location.href = url;
            return false;
        }

        this.addItem = function () {
            if ((this.selectedItem() != "") && (this.ownership.indexOf(this.selectedItem()) < 0))
            {
                // Prevent blanks and duplicates
                this.ownership.push(this.selectedItem());
                this.availableOwners.removeAll(this.selectedItem());
            }
            this.selectedItem(""); // Clear the text box
        };

        this.removeSelected = function () {
            if ((this.selectedItem() != "") && (this.availableOwners.indexOf(this.selectedItem()) < 0))
            {
                this.ownership.removeAll(this.selectedItems());
                this.availableOwners.push(this.selectedItem());
            }
            this.selectedItem("");
        };

        this.sortItems = function() {
            this.ownership.sort();
            this.availableOwners.sort();
        };
    };
ko.applyBindings(new viewModel());
var url = $("#RedirectTo").val();

When I hit the button MoveLeft or MoveRight, I get the following error:

Uncaught TypeError: undefined is not a function 
    (anonymous function) 
    jQuery.event.dispatch 
    elemData.handle

Does anyone know how to pass the selected value from listbox to addItem or removeItem function in order to add or remove objects from the list ownership?

Thanks!

Upvotes: 2

Views: 560

Answers (2)

super cool
super cool

Reputation: 6045

well niko its gonna be fun moving on with Javascript especially with ko

I forked some of you code to make things understandable to you in a better way .

In addition to the reasons mentioned by dear Wayne Ellery there are also few things you missing here like you have to use selectedOptions when there is a chance to select multiple list items

The error you given us undefined is not a function is because you are selecting multiple list items and trying to push it which is not exactly how ko push works rather you have to loop through and do it.

Check here for selectedOptions Documentation

Its always good to have a fiddle right. Here we go check the working fiddle here

There is no need of doing additional logic as you given in for click it can be done in simple readable way everything provided in fiddle

View Model:

    var vm=function() {
    var self=this;
    //observable's declaration    

    self.addItem = function () {
    ko.utils.arrayForEach(self.selectedItem1(),function(item){
    self.availableOwners.push(item);
        self.ownership.remove(item);
    });
    }

    self.removeSelected = function () {
    ko.utils.arrayForEach(self.selectedItem2(),function(item){
    self.ownership.push(item);
    self.availableOwners.remove(item)
    });
    };

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

View:

<select  multiple="multiple" data-bind="options : ownership, optionsText:function(item) { return item.FirstName() + ' ' + item.LastName()}, selectedOptions:selectedItem1"></select>

 <input class="btn btn-primary" id="MoveLeft" type="button" value=" << " data-bind="click:removeSelected,enable:selectedItem2"  />

Any issue on this get back to us .

Upvotes: 3

Wayne Ellery
Wayne Ellery

Reputation: 7958

Some minor issues with observables.

selectedItem should be initialised to empty string:

this.selectedItem = ko.observable("");

ownership should be an observableArray.

this.ownership=ko.observableArray(owners);

Here you need to evaluate ownership using this.ownership()

if ((this.selectedItem() != "") && (this.ownership().indexOf(this.selectedItem()) < 0))
{
   // Prevent blanks and duplicates
   this.ownership.push(this.selectedItem());
   this.availableOwners.removeAll(this.selectedItem());
}
this.selectedItem(""); // Clear the text box

Upvotes: 0

Related Questions