Using Knockout JS to choose which MVC partial view to load in a foreach loop

2,621 views
Skip to first unread message

colm....@gmail.com

unread,
Apr 10, 2013, 4:26:57 PM4/10/13
to knock...@googlegroups.com
Hi,
I'm just starting into developing a prototype using Knockout, in an attempt to cleanup the spaghetti code that is now js files. The current application is coded in MVC4 and uses partial views heavily.

Current MVC solution:
I have a single root page, which in turn using partial views for each of it's components. The settings for each component are fetched using a ajax query to the controller. I then loop over each element in the returned model and show the appropriate partial view based on a type property that is present. Each of these partial views in turn have quite a bit of js to display complex UI elements such as charts and grids on screen.

Knockout JS solution?
So far, I have the components with their settings in an observable array, loading via ajax from the backend. My root page then loops over these elements in the data bound array like: 

<div data-bind="foreach: Renderers">
    @Html.Partial("~/Views/Renderer/Index.cshtml")
</div>

My question is how to add an additional filter to the foreach loop to look at the type. Depending on the type, a different partial page will be shown on screen.

Patrick Steele

unread,
Apr 11, 2013, 2:32:05 AM4/11/13
to knock...@googlegroups.com
I'm not sure I completely understand your current setup, but instead of adding a filter to the foreach, you could expose a different collection of renderers that is type specific via a computed observable:

self.Grids = ko.computed(functionI() {
    var renderers = self.Renderers().slice(0);    // make a copy
    renderers.remove(function(r) { return r.Type != 'Grid'; });
    return renderers;
}

Now you can foreach on just the "Grids" property.  Hope this helps.
   

--
You received this message because you are subscribed to the Google Groups "KnockoutJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to knockoutjs+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

colm....@gmail.com

unread,
Apr 11, 2013, 9:18:49 AM4/11/13
to knock...@googlegroups.com
Hi Patrick,
Thanks for your feedback. I have considered your option as well. However, I have about 15 different types of renderers, which makes the solution below seem a little unwieldy. I would need to create 15 arrays and then do a foreach on each one to show all the partial views.

For clarity, here is how my MVC4 solution looks currently:

@model RendererSettings
<snip>
foreach (var rend in Model.Renderers)
        {    
            var parameters = new {uniqueRendererId = @Model.TemplateId + "/" + rend.name};
            switch (rend.type)
            {
                case rendererTypeEnum.chart:
                    Html.RenderAction("Index", "Chart", parameters);
                    break;
                case rendererTypeEnum.grid:
                    Html.RenderAction("Index", "Grid", parameters);
                    break;
<snip>

The solution you propose would result in:
Root.cshtml
<div data-bind="foreach: Grid">
    @Html.Partial("~/Views/Grid/Index.cshtml")
</div>
<div data-bind="foreach: Chart">
    @Html.Partial("~/Views/Chart/Index.cshtml")
</div>
Renderers.js
function Renderers() {
    var self = this;
    self.Grids = ko.computed(functionI() {
        var renderers = self.Renderers().slice(0);    // make a copy
        renderers.remove(function(r) { return r.Type != 'Grid'; });
        return renderers;
    }
    self.Charts= ko.computed(functionI() {
        var renderers = self.Renderers().slice(0);    // make a copy
        renderers.remove(function(r) { return r.Type != 'Chart'; });
        return renderers;
    }
    <snip>
}

It works, but to me, it seems like there has to be some sort of solution that can just select the correct view based on the type without needing the separate arrays. Maybe I'm wrong on that though...

Gunnar Liljas

unread,
Apr 11, 2013, 10:12:39 PM4/11/13
to knock...@googlegroups.com
You can render the partials into templates….

<script type="text/html" id="ChartTemplate">
@Html.Partial("~/Views/Chart/Index.cshtml")
</script>

And use a knockout template binding where the template name is based on the current item's type.


It's also possible to fetch the template asynchronously, using the external template engine.


/G

Francois...@krs.co.za

unread,
Apr 15, 2013, 5:02:46 PM4/15/13
to knock...@googlegroups.com, colm....@gmail.com
Hi

I'm still a newbie with knockoutjs, so not sure of the actual implementation details.  But, it sounds like you somehow need to incorporate the Strategy design pattern into the solution and find a way to use an indexer to replace the unwieldy switch statements. I have used this pattern with this kind of renderer situation in winforms before and it worked a charm.

Hope this helps
Frank

Stacey

unread,
Apr 18, 2013, 4:00:50 PM4/18/13
to knock...@googlegroups.com, colm....@gmail.com
What is that <snip> tag? I've never seen that before in ASP.NET MVC.
Reply all
Reply to author
Forward
0 new messages