-1

I'm binding some list items to a dropdown through Knockout but it's not binding. I don't know where I am going wrong..

I used the knockout mapping plugin and even tried a simple method but nothing seems to work.

My basic structure is like this:

BugsReport rp = new BugsReport()
{
     SoftwareProductList = new List<SoftProduct>() { new SoftProduct() { ProductName = "eCommerce Website", SoftProId = 1 }, new SoftProduct() { ProductName = "Banking website", SoftProId = 2 } },
     ListBugs = GetAllBugs(),
     PriorityLevels = new List<Priority>() { new Priority() { PriorityId = 1, PriorityName = "P1" }, new Priority() { PriorityId = 2, PriorityName = "P2" }, new Priority() { PriorityId = 3, PriorityName = "P3" } }
};

which i am sending from controller... Normal razor binding is happening but not knockout.

Html part

<div  style="margin-top: 10px; width: 200px; float: left; font-weight: bold;">
    Products
    <select id="slSoftProducts" multiple="multiple" data-bind="options: $root.ProductList, value:ProductList.SoftProId, optionsText: 'ProductList.ProductName'">. </select>
</div>
<div style="margin-top: 10px; width: 200px; float: left; font-weight: bold; margin-left: 30px;">
     priority Levels
     <select id="slPriorityLevels" multiple="multiple" data-bind="options: $root.priorityList, value: priorityList.PriorityId, optionsText: 'priorityList.PriorityName'"></select>
</div>

and Javascript part

function bugzillaviewmodel(){
    var self = this;
    self.ProductList = BugList.SoftwareProductList;
    self.priorityList = BugList.PriorityLevels;                         
}     

var viewModel = new bugzillaviewmodel();

// Knock Out Binding   through mapping.. 
//var viewModel = ko.mapping.fromJS(BugList);    
ko.applyBindings(viewModel);   
TrueEddie
  • 2,183
  • 2
  • 26
  • 36
Mathew
  • 132
  • 1
  • 10

5 Answers5

0

It looks like your binding references are incorrect, you have the object prepended to the name of the properties you want. Try this:

        <div  style="margin-top: 10px; width: 200px; float: left; font-weight: bold;">
            Products
            <select id="slSoftProducts" multiple="multiple" data-bind="options: ProductList, value: SoftProId, optionsText: 'ProductName'"></select>
        </div>
        <div style="margin-top: 10px; width: 200px; float: left; font-weight: bold; margin-left: 30px;">
            priority Levels
          <select id="slPriorityLevels" multiple="multiple" data-bind="options: priorityList, value: PriorityId, optionsText: 'PriorityName'"></select>
        </div>

You also need to make the properties that you are binding to observables. Have a look at the mapping plugin to make self.ProductList and self.priorityList observable properties of your view model.

I've also removed the $root reference, as I don't think you need it there.

Paul Manzotti
  • 5,107
  • 21
  • 27
  • hi Itried ur changes it gives me script error...Microsoft JScript runtime error: Unable to parse bindings. Message: TypeError: 'SoftProId' is undefined; Bindings value: options: ProductList, value:SoftProId, optionsText: 'ProductName' – Mathew Feb 19 '13 at 12:24
  • Then you need to make the properties observable for Knockout to be able to use them. – Paul Manzotti Feb 19 '13 at 12:36
  • to make properties observable i used mapping pluin viewModel = ko.mapping.fromJS(BugList); which will convert the viewmodel into observable properties. Still then values are not binding. – Mathew Feb 19 '13 at 12:42
  • Could you create a jsFiddle to demonstrate your problem then? – Paul Manzotti Feb 19 '13 at 12:45
  • Here's one I've previously created: http://jsfiddle.net/gvBXh/2/ You need to make sure you add in Knockout and the mapping plugin from a CDN in the Manage Resources section on the menu on the left. – Paul Manzotti Feb 19 '13 at 13:03
0

SoftProId and PriorityId aren't defined anywhere. If the it is contained within the ProductList object then it should be something like.

<select id="slSoftProducts" multiple="multiple" data-bind="options: ProductList.List, value: ProductList.SoftProId, optionsText: 'ProductName'"></select>

With your view model

function bugzillaviewmodel(){
   var self = this;
   self.ProductList = BugList.SoftwareProductList;
   self.priorityList = BugList.PriorityLevels;
   self.SoftProId = ko.observable();
   self.PriorityId = ko.observable();
} 

But not knowing the structure of your objects I can't tell for sure

Andrew Davis
  • 460
  • 3
  • 17
  • i am Using this @Html.Raw(Json.Encode(Model)); to get object. The structure is already there in the question at the top. – Mathew Feb 19 '13 at 12:35
  • So in the case of your first select the variable 'SoftProId' doesn't exist anyway in your view model, and it's the same for 'PriorityId'. Add those to the view model and the code @PaulManzotti will work correctly. Paul was also correct about not needing $root as you're in a loop or child object. – Andrew Davis Feb 19 '13 at 12:42
  • both 'SoftProId' and 'PriorityId' are properties of class you can see them in the structure i am making in the controller in the question. The same object i ll get when i do the @Html.Raw(Json.Encode(Model)); so both are there in the iewModel.. – Mathew Feb 19 '13 at 12:58
  • Your view model is 'bugzillaviewmodel'. Is that not the complete definition of your object? – Andrew Davis Feb 19 '13 at 13:00
  • Just add `self.SoftProId = ko.observable()` and `self.PriorityId = ko.observable()` to your view model – Andrew Davis Feb 19 '13 at 14:11
0

You have two problems :

  1. You wrote 'ProductList.ProductName' in optiosnText instead of just 'ProductName'
  2. For the value, it is not the value (the html value) of the option like you was thinking but it is the value that will be stocked in a variable in your view model, for example "selectedProduct" which will be an observable

I think this should work :

<div style="margin-top: 10px; width: 200px; float: left; font-weight: bold;">
    Products
    <select id="slSoftProducts" multiple="multiple" data-bind="options: ProductList, value:productSelected, optionsText: 'ProductName'">. </select> </div>
<div> style="margin-top: 10px; width: 200px; float: left; font-weight: bold;margin-left: 30px;">
priority Levels
    <select id="slPriorityLevels" multiple="multiple" data-bind="options: priorityList, value:prioritySelected, optionsText:'PriorityName'"></select>
</div>

the js part :

function bugzillaviewmodel(){
    var self = this;
    self.ProductList = BugList.SoftwareProductList;
    self.priorityList = BugList.PriorityLevels;                         
    self.productSelected = ko.observable(); // Will contain the selected product object from the ProductList
    self.prioritySelected = ko.observable(); // same but from the priorityList
}     

var viewModel = new bugzillaviewmodel();

// Knock Out Binding   through mapping.. 
//var viewModel = ko.mapping.fromJS(BugList);    
ko.applyBindings(viewModel);   
Adam Cherti
  • 962
  • 1
  • 8
  • 21
0

function bugzillaviewmodel(){
    var self = this;
    self.ProductList = BugList.SoftwareProductList;
    self.priorityList = BugList.PriorityLevels;  
    self.SelectedProductId = ko.observable();
    self.SelectedPriorityId = ko.observable();
}     

var viewModel = new bugzillaviewmodel();

// Knock Out Binding   through mapping..  
ko.applyBindings(viewModel);
<div  style="margin-top: 10px; width: 200px; float: left; font-weight: bold;">
            Products
            <select id="slSoftProducts" multiple="multiple" data-bind="options: ProductList, optionsValue: SoftProId, optionsText: 'ProductName', value: SelectedProductId"></select>
        </div>
        <div style="margin-top: 10px; width: 200px; float: left; font-weight: bold; margin-left: 30px;">
            priority Levels
          <select id="slPriorityLevels" multiple="multiple" data-bind="options: priorityList, optionsValue: PriorityId, optionsText: 'PriorityName', value: SelectedPriorityId"></select>
</div>
0

Try this...

On the server have a property on your Razor ViewModel that returns the serialized object or list of objects:

public string SelectListToJson {
        get
        {
            return JsonConvert.SerializeObject(YourSelectList);
        }
    }

In the View have this:

//DTO objects definition for mapping
var SoftProduct = function(dto){
 var self = this;
  self.ProductName = ko.observable(dto.ProductName);
  self.SoftProId = dto.SoftProId;
};

var Priority = function(dto){
 var self = this;
  self.PriorityId = dto.PriorityId;
  self.PriorityName = ko.observable(dto.PriorityName);
};

//Output from Razor "@Html.Raw(Model)"
//I.E. var BugList = @Html.Raw(Model)
var BugList = {
 SoftwareProductList: [
   { ProductName: "eCommerce Website", SoftProId: 1},
    { ProductName: "Banking Website", SoftProId: 2},
  ],
  PriorityLevels: [
   {PriorityId: 1, PriorityName: "P1"},
    {PriorityId: 2, PriorityName: "P2"},
    {PriorityId: 3, PriorityName: "P3"},
  ]
};

//define main view model to apply bindings to
var bugzillaviewmodel = function(){
    var self = this;
    self.ProductList = ko.mapping.fromJS([]);
    self.PriorityList = ko.mapping.fromJS([]);
    self.SelectedProducts = ko.observableArray();
    self.SelectedPriorities = ko.observableArray();
};


  //init viewModel
  var viewModel = new bugzillaviewmodel();

  //map data in BugList to viewmodel
   ko.mapping.fromJS(
                   BugList.SoftwareProductList,
                   {
                       key: function (data) {
                           return ko.utils.unwrapObservable(data.SoftProId);
                       },
                       create: function (options) {
                           return new SoftProduct(options.data);
                       }
                   },
                   viewModel.ProductList);
   ko.mapping.fromJS(
                   BugList.PriorityLevels,
                   {
                       key: function (data) {
                           return ko.utils.unwrapObservable(data.PriorityId);
                       },
                       create: function (options) {
                           return new Priority(options.data);
                       }
                   },
                   viewModel.PriorityList);

  //apply bindings to dom                 
  ko.applyBindings(viewModel); 
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>

<div style="margin-bottom:20px;height:150px;">
  <div  style="margin-top: 10px; width: 200px; float: left; font-weight: bold;">
      Products<br/>
       <select id="slSoftProducts" multiple="true" data-bind="options: ProductList,optionsText: 'ProductName', optionsValue: 'SoftProId', selectedOptions: SelectedProducts"></select>   
  </div>
  <div style="margin-top: 10px; width: 200px; float: left; font-weight: bold; margin-left: 30px;">
       Priority Levels<br/>
       <select id="slPriorityLevels" multiple="true" data-bind="options: PriorityList, optionsText:'PriorityName', optionsValue:'PriorityId', selectedOptions: SelectedPriorities"></select>
  </div>
</div>


<div >
        <textarea rows="20" cols="100" data-bind="text: ko.toJSON($data, null, 2)"></textarea>
    </div>
Zach Painter
  • 130
  • 6