Reputation: 66565
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
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
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