In my last blog post I did a quick overview of the Razor ViewEngine and showed a few examples of the new syntax working with the Telerik Extensions for ASP.NET MVC.  If you haven’t read over the blog post yet I recommend that you do before you continue reading this one, especially if you are not familiar with the Razor ViewEngine yet.

Today I wanted to take a look at a how the new Razor ViewEngine works with our Grid for ASP.NET MVC, specifically in terms of Server Hierarchy. Why just Server and not Ajax you say? Well the WebForms code is pretty much the same for the Ajax hierarchy, aside from the @{ … } syntax of Razor, so there really isn’t any new excitement going on there.

Now one quick MVC3 item that I want to bring up here is the @helper syntax. This syntax allows you to declare re-usable HTML helpers which help encapsulate HTML generation functionality. You can simply define an @helper { … } section somewhere in your View and then call it anywhere you want that HTML placed on the page. Let’s look over a quick example. As we can see below I have defined “HelperFunction” which simply takes an integer and populates a list accordingly.

@helper HelperFunction(int i)
{
    <ul id="Employees">
        @for(int a = 1; a <= i; a++)
        {
            <li>List Item #@a</li>
        }
    </ul>
}
Then in order to call this function I simply type @ and then start typing the name of my function, intellisense should pick it right up:

<div>
    @HelperFunction(10)
</div>
This is of course a very simplified use of this functionality, but it gets the point across.

Next I’ll start creating my Grid hierarchy. We’ll start off like we usually do, and as we saw in the previous blog post we’ll use @<text></text> to define our first level of hierarchy:

@{Html.Telerik().Grid(Model)
      .Name("Employees")
      .Columns(columns =>
      {
          columns.Bound(e => e.FirstName);
          columns.Bound(e => e.LastName);
          columns.Bound(e => e.Title);
          columns.Bound(e => e.Country);
          columns.Bound(e => e.City);
      })
      .DetailView(detailView => detailView.Template(
          @<text>
            @(Html.Telerik().Grid(item.Orders)
                  .Name("Orders_" + item.EmployeeID)
                  .Columns(columns =>
                  {
                      columns.Bound(o => o.OrderID);
                      columns.Bound(o => o.ShipCountry);
                      columns.Bound(o => o.ShipName);
                      columns.Bound(o => o.ShippedDate);
                  })
                  .Pageable(paging => paging.PageSize(5))
                  .Sortable()
             )
          </text>
          ))
      .Pageable(paging => paging.PageSize(5))
      .Sortable()
      .Render();
 }

Easy enough! Let’s see what happens when we define a third level hierarchy using the same way:

@{Html.Telerik().Grid(Model)
      .Name("Employees")
      .Columns(columns =>
      {
          columns.Bound(e => e.FirstName);
          columns.Bound(e => e.LastName);
          columns.Bound(e => e.Title);
          columns.Bound(e => e.Country);
          columns.Bound(e => e.City);
      })
      .DetailView(detailView => detailView.Template(
          @<text>
            @(Html.Telerik().Grid(item.Orders)
                  .Name("Orders_" + item.EmployeeID)
                  .Columns(columns =>
                  {
                      columns.Bound(o => o.OrderID);
                      columns.Bound(o => o.ShipCountry);
                      columns.Bound(o => o.ShipName);
                      columns.Bound(o => o.ShippedDate);
                  })
                  .DetailView(ordersDetailView => ordersDetailView.Template(
                      @<text>
                            @(Html.Telerik().Grid(item.Order_Details)
                                  .Name("OrderDetails_" + o.EmployeeID + "_" + o.OrderID)
                                  .Columns(columns =>
                                  {
                                      columns.Bound(od => od.Product.ProductName);
                                      columns.Bound(od => od.Quantity);
                                      columns.Bound(od => od.UnitPrice);
                                      columns.Bound(od => od.Discount);
                                  })
                                  .Pageable(paging => paging.PageSize(5))
                                  .Sortable()
                             )
                      </text>
                    ))
                  .Pageable(paging => paging.PageSize(5))
                  .Sortable()
             )
          </text>
          ))
      .Pageable(paging => paging.PageSize(5))
      .Sortable()
      .Render();
 }
When we open this in the browser we’re greeted by the following error message:

"Parser Error Message: Inline markup blocks (@<p>Content</p>) cannot be nested.  Only one level of inline markup is allowed."

As the error message mentions, the Razor ViewEngine does not support any further nesting of @<p>, <text> or <div> tags. So what can we do in situations where we need more than one level of hierarchy? Here’s where the helpers that I mentioned come into play, aren’t you glad I mentioned them? :) So here’s how we can define and use our helper:

@helper OrdersDetailViewTemplate(WebViewPage page, TelerikMVCTestApp.Models.Order o)
{
    @(Html.Telerik().Grid(o.Order_Details)
          .Name("OrderDetails_" + o.EmployeeID + "_" + o.OrderID)
          .Columns(columns =>
          {
              columns.Bound(od => od.Product.ProductName);
              columns.Bound(od => od.Quantity);
              columns.Bound(od => od.UnitPrice);
              columns.Bound(od => od.Discount);
          })
          .Pageable(paging => paging.PageSize(5))
          .Sortable()
     )
}

 

@{Html.Telerik().Grid(Model)
      .Name("Employees")
      .Columns(columns =>
      {
          columns.Bound(e => e.FirstName);
          columns.Bound(e => e.LastName);
          columns.Bound(e => e.Title);
          columns.Bound(e => e.Country);
          columns.Bound(e => e.City);
      })
      .DetailView(detailView => detailView.Template(
          @<text>
            @(Html.Telerik().Grid(item.Orders)
                  .Name("Orders_" + item.EmployeeID)
                  .Columns(columns =>
                  {
                      columns.Bound(o => o.OrderID);
                      columns.Bound(o => o.ShipCountry);
                      columns.Bound(o => o.ShipName);
                      columns.Bound(o => o.ShippedDate);
                  })
                  .DetailView(ordersDetailView => ordersDetailView.Template(o => OrdersDetailViewTemplate(this, o)))
                  .Pageable(paging => paging.PageSize(5))
                  .Sortable()
             )
          </text>
          ))
      .Pageable(paging => paging.PageSize(5))
      .Sortable()
      .Render();
 }

As we can see in the code snippets above, we define a helper function that allows us to pass our View as well as an Order entity. We can then define the Grid structure that we want for this level of hierarchy and call it when we are defining the template.

So that’s it! We now can define a hierarchy as deep as we would want without running into any snares due to nested markup blocks using the new Razor syntax!


About the Author

Carl Bergenhem

is an Enterprise Solutions Consultant at Telerik specializing in the ASP.NET AJAX and ASP.NET MVC products. He has always been interested in web development and has played around with various web technologies since he was a kid. In his free time Carl enjoys soccer, running and playing his guitar.

@carlbergenhem

Related Posts

Comments