InvaderZim
InvaderZim

Reputation: 93

Knockout: Modular Views Based On Model Field

Question: Is it possible to have different views for a model based on the value it has for a field?

Explanation: I have a model with a Settings and Type field in it. The settings can be different settings model based on the type. I would like to switch out the view for the settings based on the value of Type.

I have minor experience with knockout, and would like this to scalable for many different types.

I tried using a ko.computedObservable with a switch statement to return a function() that defines the settings in it; such as:

self.Settings = ko.computed(function () {

    switch (self.Type()) {

        case "Type1":

            return new Type1(model.Settings);

        case "Type2":

            return new Type2(model.Settings);
    }

});

Type1 and Type2 are functions with the unique settings for each type of the model. This failed miserably.

I may just be over complicating the problem, so a second pair of eyes and any suggestions would be fantastic!

Thank you in advance!

Upvotes: 1

Views: 66

Answers (1)

James Thorpe
James Thorpe

Reputation: 32202

Consider using templates for your different views. By doing so, you can then make use of the ability to dynamically choose which template is rendered based on a property of your viewmodel. For example, assuming your viewmodel looks something like:

var vm = function() {
    var self = this;
    self.Settings = ko.computed(function () {
        switch (self.Type()) {
            case "Type1":
                return new Type1(model.Settings);

            case "Type2":
                return new Type2(model.Settings);
        }
    });

    //Based on your example computed, we'll return a different template name
    //for each object type you're returning
    self.templateName = function(t) {
        if (t instanceof Type1)
            return "template_type1";
        if (t instanceof Type2)
            return "template_type2";

        return "template_unknown";
    }
};

Your main view then binds to your collection as normal, but with the template binding making use of the function defined on your viewmodel:

<div data-bind="template: { name: templateName, foreach: Settings }"></div>

You can then include templates in your script that bind to specific properties of each type:

<script id="template_type1" type="text/html">
    <span data-bind="text: name"></span>
</script>
<script id="template_type2" type="text/html">
    <h3 data-bind="text: title"></h3>
</script>
<script id="template_unknown" type="text/html">
    <span>Unknown item type</span>
</script>

Upvotes: 2

Related Questions