Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kendo UI MVVM - How to iterate over and render a collection within a view?

I'm simply trying to loop over an array within my Kendo.View and attempting to render a property from the element. This would be super simple in MVC Razor, e.g.

@foreach( var displayLink in Model ) {
 <h1>displayLink.Text</h1>
}

Rather than choosing excerpts I just shared the entire files.

This all runs, no exceptions, etc. The view renders the static content but doesn't render the contents of the loop. I turned on evalTemplate = true, but still no dice. I haven't been able to find any way to do this and it's driving me nuts. All I can find is ways to wire up a Kendo UI ListView or such. I don't want that weight, I just want to loop over the array directly.

Index.htm (view):

<div class="jumbotron">
    <div class="container">
        <h1>Web</h1>
        <p>The future is <i>now</i>.
        </p>
    </div>
</div>


# for(var i = 0; i < DashboardLinks.length; i++) { #
    <h1>#= DashboardLinks[i].TitleText #</h1>
# } #

Controller:

define(
    // == INTERFACE NAME ==
    "Controllers.IHome", 

     // == DEPENDENCIES ==
    [
        "Util.IGetViewSource", 
        "Util.ILayout",
        "ViewModels.Home.IHomeVM"
    ],

    function ( /* Dependency injections: */ getViewSource, layout, iHomeVM)
    {

        // Define the module.
        var module =
           {
               index: function () {

                   getViewSource("~/App/Views/Home/Index.htm", function (viewSource) {
                       // get the model
                       var viewModel = new iHomeVM();
                       viewModel.AddDashboardLink("#timecard", "Time Cards", "Manage time cards and get it done.", "time");

                       // render the view
                       var view = new kendo.View(viewSource, { model: viewModel, evalTemplate: true });

                       // render the view
                       layout.renderBodyView(view);
                   });
               }
           };

        // Return the module.
        return module;
    }
);

HomeVM:

define(
    // == INTERFACE NAME ==
    "ViewModels.Home.IHomeVM",

    // == DEPENDENCIES ==
    [
        "ViewModels.Shared.ILinkVM"
    ],
    function(
        // == DEPENDENCY INJECTIONS ==
        iLinkVM
    ) {
        // == CONSTRUCTOR ==
        function HomeVM() {
            console.log("HomeVM constructor executing.");


            // == PROPERTIES & METHODS ==
            this.DashboardLinks = [];


            // Return a copy of this wrapped in Kendo's observable.
            return kendo.observable(this);
        }

        HomeVM.prototype.AddDashboardLink = function(
            href,
            titleText,
            descriptionText,
            iconName) {
            this.DashboardLinks.push(new iLinkVM(
                href,
                titleText,
                descriptionText,
                iconName
            ));
        } 

        // Return the view model module.
        return HomeVM;
    }
);

LinkVM:

define(
    // == INTERFACE NAME ==
    "ViewModels.Shared.ILinkVM",  

    // == DEPENDENCIES ==
    [

    ],

    function (
        // == DEPENDENCY INJECTIONS ==

    )
    {
        // == CONSTRUCTOR ==
        function LinkVM(href, titleText, descriptionText, iconName) {
            console.log("LinkVM constructor executing.");


            // == PROPERTIES & METHODS ==
            this.Href = href;
            this.TitleText = titleText;
            this.DescriptionText = descriptionText;
            this.IconName = iconName;


            // Return a copy of this wrapped in Kendo's observable.
            return kendo.observable(this);
        }


        // Return the view model module.
        return LinkVM;
    }
);
like image 508
Andrew Lundgren Avatar asked Oct 20 '22 12:10

Andrew Lundgren


2 Answers

At a glance, it appears you are missing some steps with your Kendo templating. Specifically, you need to define a template in a <script type="text/x-kendo-template"> tag and pass data to it. For the example I am crafting, this would be represented as such

<script id="myTemplate" type="text/x-kendo-template">
    # for (var i = 0; i < data.DashboardLinks.length; i++) { #
        <h1>#= data.DashboardLinks[i].TitleText #</h1>
    # } #
</script>

Then in order to use this, we can leverage these Kendo functions to dynamically render our template - which we can inject into our DOM

var template = kendo.template($("#myTemplate").html()); // notice id on <script>

var data = { DashboardLinks: [{TitleText : 'LinkA'}, {TitleText: 'LinkB'}, {TitleText: 'LinkC'}] };

var result = template(data);

notice how we pass data to our template(data). This function renders our template and in fact if we console.log(result) at this point we see our rendered template

<h1>LinkA</h1>
<h1>LinkB</h1>
<h1>LinkC</h1>

It's then possible to call .html(result) to inject our rendered markup into our DOM

Source: Kendo UI Templates Overview

Working example: Kendo UI Dojo

like image 117
scniro Avatar answered Oct 22 '22 02:10

scniro


I found it: you can do this via setting the "evalTemplate" property: http://docs.telerik.com/kendo-ui/api/javascript/view#configuration-evalTemplate

  // create the view
  var view = new kendo.View(viewSource, { model: viewModel, evalTemplate: true });

Then you can use MVVM declarative binding and also Kendo template binding, such as a for loop.

Ensure you're properly escaping all of your hashes ('#'), otherwise the templating will blow up.

like image 29
Andrew Lundgren Avatar answered Oct 22 '22 02:10

Andrew Lundgren