Sam
Sam

Reputation: 14596

knockout binding issue

I use mapping plugin for creating the view model. Here's the watcher output from Chrome:

viewModel: Object
 Id: function observable() 
 Language: function observable() 
 QuoteListViewModel: Object
 QuoteSelectedViewModel: Object

The MVC Model is :

public class QuoteRequestViewModel
{
    public Guid Id { get; set; }
    public LanguageEnum Language { get; set; }   

    public QuoteViewModel QuoteSelectedViewModel { get; set; }
    public QuoteListViewModel QuoteListViewModel { get; set; }
}

The QuoteViewModel is :

public class QuoteViewModel
{
    public string ProductName { get; set; }
    public decimal MonthPrice { get; set; }
    public decimal QuarterPrice { get; set; }
    public decimal BiannualPrice { get; set; }
    public decimal YearPrice { get; set; }

    public List<CoverQuoteViewModel> CoverQuotesViewModel { get; set; }
}

The QuoteListViewModel is not relevant here and actually works fine.

Two questions:

1) Why is QuoteSelectedViewModel mapped as an Object instead of an Observable function ? I understand why it's the case for QuoteListViewModel because it's an Array, but QuoteSelectedViewModel is not an Array.

2) I can't bind my DOM to QuoteSelectedViewModel. Here's what I do:

viewModel.customizeQuote = function () {
  viewModel.QuoteSelectedViewModel = this;
}

and customizeQuote is called there:

<table data-bind="with: QuoteListViewModel">
 <tbody>
 <tr data-bind="foreach: Quotes">
  <td>
    <a class="btn btn-primary" href="#" data-bind="click: $root.customizeQuote">Customize</a>
 </td>
 </tr>

When debugging, I can see that QuoteSelectedViewModel contains the correct Quote from the QuoteListViewModel Array. However doing:

viewModel.QuoteSelectedViewModel = this; 

seems incorrect to me. It should be an observable and I should do

viewModel.QuoteSelectedViewModel( this );

Any idea what's wrong ?

[EDIT]

The fact that QuoteSelectedViewModel is not observable is obviously the root of the problem.

I've added the following code:

viewModel.SelectedQuote = ko.observable(viewModel.QuoteSelectedViewModel);

and in the customize method I do this instead:

viewModel.SelectedQuote(this);

So now, the list is bound. So how do I make the QuoteSelectedViewModel an observable object right from the beginning when I use the mapping plugin ?

Upvotes: 0

Views: 120

Answers (1)

RP Niemeyer
RP Niemeyer

Reputation: 114792

The mapping plugin creates observables for the lowest level properties and arrays. For nested objects it does not make the parent an observable.

var test = {
   sub: {
       name: "Bob"
   }
};

In this case, it will make name an observable, but sub will not be observable.

One option is to customize how objects are created using the mapping options, as described here.

Upvotes: 1

Related Questions