Friday, 16 August 2013

Using Display Templates or Editor Templates

DisplayTemplates or EditorTemplates is used for providing custom template for a model property whether it is of a single object type or a collection of an object type. DisplayTemplates or EditorTemplates can be used to automatically render an object type in all views in the application or in all views of a particular controller. It can also only be called when needed.

To use that, first create the template (view) for the object type with this name 'object_type.cshtml' under DisplayTemplates or EditorTemplates folder under Views\Shared or a particular controller's views folder (e.g.; Views\Home). By default the framework will search under a controller views folder first then the Shared folder. If we put the template under Shared folder then it will apply to all views. Whenever a particular object type is rendered using EditorFor or DisplayFor, the framework will use the template.

For example, below is a template for a class object type called ItemViewModel:
@model ItemViewModel

@Html.DisplayNameFor(model => model.ItemId)
@Html.DisplayFor(model => model.ItemId)

@Html.DisplayNameFor(model => model.ItemName)
@Html.DisplayFor(model => model.ItemName)

Then render the property with EditorFor or DisplayFor helper method on a view.
EditorFor(model => model.Items)

That's all that we need to do. If the property is a collection of an object type then the template will be rendered multiple times for each item.

If we want the new template to be used only when we call it, then we could name the template using other name other than the object type (e.g.; MyCustomTemplate.cshtml). Then to use it we can specify the template name as the second argument on EditorFor or DisplayFor method
EditorFor(model => model.Items, "MyCustomTemplate")
or by using UIHint attribute on the object property
[UIHint("MyCustomTemplate")]
public IList<ItemViewModel> Items { get; set; }

Friday, 9 August 2013

Passing Dynamic Collection Member Manually through Html.BeginForm Method

Let's say we have a model with a collection type member that is populated dynamically on client side and we want to pass them automatically to controller by using Html.BeginForm(). We can manually add html input elements with some conventions to allow the collection to be passed.
The input element must have:
- id attribute like 'CollectionName_IndexNumber__PropertyName'
- and name attribute like 'CollectionName[IndexNumber].PropertyName'

For example, if we have:
public class InvoiceDto
{
 public int InvoiceId { get; set; }
 public string Name { get; set; }    
 public string Description { get; set; }

 public IList<ItemSellingDto> Items { get; set; }
}

public class ItemSellingDto
{
 public int ItemSellingId { get; set; }
 public int ItemId { get; set; }
 public Int16 Quantity { get; set; }     
 public decimal Price { get; set; }
 public int InvoiceId { get; set; }
}
and we would like to add each collection member (ItemSellingDto) to an html table element inside Html.BeginForm() dinamically using JavaScript (see my previous post to see the example layout), then the script would look like something like:
function addRow(response) {
 var tableRows = $('#tblItemSellings tr');
 var tr;
 tr = $('<tr/>');
 tr.append("<td>" + response.ItemName + "</td>");
 tr.append("<td>" + response.Quantity + "</td>");
 tr.append("<td>" + response.Price + "</td>");

    // the first row is for table headers
 tr.append("<td><input type='hidden' id='Items_" + (tableRows.length - 1) + "__ItemId' name='Items[" + (tableRows.length - 1) + "].ItemId' value='" + response.ItemId + "'/></td>");
 tr.append("<td><input type='hidden' id='Items_" + (tableRows.length - 1) + "__Quantity' name='Items[" + (tableRows.length - 1) + "].Quantity' value='" + response.Quantity + "'/></td>");
 tr.append("<td><input type='hidden' id='Items_" + (tableRows.length - 1) + "__Price' name='Items[" + (tableRows.length - 1) + "].Price' value='" + response.Price + "'/></td>");

 $('#tblItemSellings').append(tr);
}