1

In other MVVM API's for other frameworks, for example Caliburn Micro for WPF you can sub class view models. As an example I have this view model

Customer
Id : int
Selected : bool
Name : string
Edit : ViewModel

Depending on different Customer types I will have different Edit ViewModels, in Caliburn micro it would have automaticly rendered the correct view depending on the type of the ViewMOdel, types are offcourse not present in JS, but can you achive this some way in Knockout?

Anders
  • 17,306
  • 10
  • 76
  • 144
  • Do you want to achieve something like this : http://stackoverflow.com/questions/6706281/knockoutjs-can-we-create-a-dependentobservable-function-with-a-parameter – Subodh Mar 16 '12 at 09:46
  • Not really no, I want to bind the Edit ViewModel to different Views (different html templates) depending on the "type" of viewmodel. – Anders Mar 16 '12 at 10:18

2 Answers2

1

Thanks Mike, your solution is not exactly what I needed, Im doing something similar server side though, but our json-objects are read from a CQRS read model repository.

It turns out that named templates was what I was after.. Heres a little fiddle that shows what i did (In our real scenario the properties of the submodel will be on the actual customer object)

http://jsfiddle.net/Z7gMN/1/

Update: Just saw that this answer got upvoted. There are more elegant ways of doing it, for example use my Convention over configuration library found here

https://github.com/AndersMalmgren/Knockout.BindingConventions

It has a convention for templates that uses the type so use a OO pattern of your liking like this one

http://ejohn.org/blog/simple-javascript-inheritance/

Define the different types, important is that they are postfixed with Model or ViewModel

The templates should have the same name but postfixed View

<script type="text/html" id="MyView">
    <input data-name="myValue" />
</script>  

http://jsfiddle.net/JKXaX/5

Anders
  • 17,306
  • 10
  • 76
  • 144
0

I have done something similar to what I think you want to do.

What I do is to create view models on the server, serialize them into json and use the mapping plugin to create Knockout viewmodels.

I have a common base class in C# and implementation classes that have various data structures. Then I only define behaviour in knockout.

Something like this:

public abstract MyBase : IDefineMyBase {
    public string Type { get { return this.GetType().Name; } }
}

public class MyFirstEditModel : MyBase {
    public string Something { get; set; }
}

I use ASP.NET MVC to serve this to knockout:

public ActionResult MyAction() {
   var model = {
       EditModels = new IDefineMyBase[] {
           new MyFirstEditModel {
               Something = "Some thing"
           },
           ... other implementations
       }
   };

   // AsJson is a serialization extension method
   return View("MyView", (object)model.AsJson()); 
}

In Knockout, I use it like this:

// This is a behaviour base "template" that will be applied for all editmodels
var editModel = function(data) {
    // Map the edit model specific data to *this*
    ko.mapping.fromJS(data, {}, this);

    // Apply implementation specific behaviour to this instance of the model
    eval(this.Type() + '(this)'); // example: MyFirstEditModel(this);
}

// This is specific behaviour for MyFirstEditModel
var MyFirstEditModel = function(base) {
    base.someBindableSpecificFunction = function() {
        // You can use data from the implementation here.
        alert(base.Something());
    };
}

// This is the base view model where you can have all the main functionality
var viewModel = function(base) {
    ko.utils.arrayForEach(data.EditModels(), function (editModel) {
        s.Parent = base;
        // example: base.MyFirstEditModel = editModel;
        eval('base.' + s.Type() + ' = editModel');
    });
}

// This is mapping instructions
var mapping = {
    'EditModels': {
        create: function (options) {
            return new editModel(options.data);
        }
    }
};

$(document).ready(function () {
    // Map the server side model to knockout
    var mapped = ko.mapping.fromJS(@Html.Raw(Model), mapping, vm);
    // Add behaviour to the mapped data
    viewModel(mapped);
    ko.applyBindings(vm);
});

Hmm. That turned out to be a bit of code. This is how I bridge the gap between the server and the client while still being able to choose models based on Type name and things like that. It also lets me define data structures on the server while defining presentation specific behaviour in knockout view models. The mapping plugin is a bit magical but one drawback is that you don't see the data structure in the knockout viewmodels, but I have accepted that. And also, note that the casing of names differ and if you can't stand that the Newtonsofts Json serializer can change casing when serializing. I have chosen not to do so since it helps me see what is from the server and what I have defined in the view models.

Mikael Östberg
  • 16,982
  • 6
  • 61
  • 79
  • I use a separate chunk of html for template (not jquery/ko templates) and the use the with binding like so `with: MyFirstEditModel`. For common stuff within that chunk you can call ko templates. – Mikael Östberg Mar 16 '12 at 11:22
  • Hmm, ok, I was hoping they would have something built in, feels like a pretty standard MVVM behavior that you want dynamic binding of view templates... oh well – Anders Mar 16 '12 at 11:28
  • You can call ko templates from code, which might help in your case. – Mikael Östberg Mar 16 '12 at 11:32
  • you mean ko.applyBindings(model, htmlElement)? Thats no good in this scenario since it will take the template data in that element and render the content of the model in said element. – Anders Mar 16 '12 at 12:16
  • No, like in this question: http://stackoverflow.com/questions/9641063/calling-template-from-a-knockoutjs-binding – Mikael Östberg Mar 16 '12 at 12:19
  • I'll have to look more into it, but I think its a named template I wanna do http://knockoutjs.com/documentation/template-binding.html – Anders Mar 16 '12 at 12:53