I have been working with an issue for a while and cannot seem to get around it. I have a view with a Telerik tab strip. The View contains a single Data Model of couse with some tabs showing information in the top level of the data model and other tabs showing child and in one case grandchild information. In tab showing child and grandchild information from the data model I have a grid that containing the child and grandchild information. I have set the binding on this grid to be server side and to be able to Edit, Update and Delete rows in the grid using a popup form. I also have created a editor template that will show the row selected from the grid along with its child item(s).
For each of the tabs' content I have created partial views rather than placing all the content in one file and showing the partial view with the command:
@model JWITS.UserManagement.Areas.TicketApproval.Models.Ticket
@{
ViewBag.Title = "Edit";
}
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script type="text/javascript">
function onRowDataBound(e) {
var grid = $(this).data('tGrid');
// Expand the first row only
if (grid.$rows().index(e.row) == 0) {
grid.expandRow(e.row);
}
}
</script>
@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
@Html.HiddenFor(model => model.TicketGuid)
Html.Telerik().TabStrip().Name("TicketEdit").Items(items =>
{
items.Add().Text("Ticket Info").Content(() => Html.RenderPartial("EditTicketInfo",Model));
items.Add().Text("Totals").Content(() => Html.RenderPartial("EditTicketTotals", Model));
items.Add().Text("Customer").Content(() => Html.RenderPartial("EditTicketCustomer",Model));
items.Add().Text("Well Info").Content(() => Html.RenderPartial("EditTicketWellInfo", Model));
items.Add().Text("Job Data").Content(() => Html.RenderPartial("EditTicketJobData", Model));
items.Add().Text("Crew Members").Content(() => Html.RenderPartial("EditTicketCrewMembers", Model.CrewMembers) );
items.Add().Text("Well Data").Content(() => Html.RenderPartial("EditTicketWellData", Model));
items.Add().Text("Pipe Data").Content(() => Html.RenderPartial("EditTicketPipeData", Model));
items.Add().Text("Pipe Data").Content(() => Html.RenderPartial("EditsServicesItem", Model));
}).Render();
<p>
<input type="submit" value="Save" />
</p>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@Html.Telerik().ScriptRegistrar()
For the partial view of the tab item with the grid data it is rendered as so:
@{Html.Telerik().Grid(Model.ServicesItems ).Name("ServiceItems")
.DataKeys(k =>
{
k.Add(c => c.LineItemId).RouteKey("lineitemguid");
k.Add(c => c.TicketGuid).RouteKey("ticketguid");
})
.Editable(e => e.Mode(GridEditMode.PopUp))
.ToolBar(commands =>
{
commands.Insert();
})
.DataBinding( binding => binding.Server()
.Select("EditServicesItem", "Approval" )
.Insert("InsertServiceItem","Approval")
.Update("UpdateServiceItem","Approval")
.Delete("DeleteServiceItem","Approval")
)
.Columns(columns =>
{
columns.Bound(l => l.ServiceName).Width(200).Title("Service")/*.ClientTemplate("<#= ServiceName #>")/*.Template(@<text> m.ServiceName </text> )*/;
columns.Bound(l => l.BookPrice).Width(100).Title("Book Price")/*.ClientTemplate("<#= BookPrice #>")/*.Template(@<text> m.BookPrice </text>)*/;
columns.Bound(l => l.ServiceDiscount).Width(100).Title("Discount")/*.ClientTemplate("<#= ServiceDiscount #>")/*.Template(@<text> m.ServiceDiscount </text>)*/;
columns.Bound(l => l.CustomerPrice).Width(100).Title("Customer Price")/*.ClientTemplate("<#= CustomerPrice #>")/*.Template(@<text> m.CustomerPrice </text>)*/;
columns.Bound(l => l.IsPerforating).Width(50).Title("Is Perforating");
columns.Bound(l => l.LineItemId).Title("Line Item Id").Hidden()/*.ClientTemplate("<#= LineItemId #>")/*.Template(@<text> m.LineItemId </text>)*/;
columns.Bound(l => l.ShowChildren).Title("Show Children").Hidden();
columns.Bound(l => l.ChildItems).Title("Child Items").Hidden();
columns.Command(commands =>
{
commands.Edit().ButtonType(GridButtonType.Text);
commands.Delete().ButtonType(GridButtonType.Text);
}
).Width(100).Title("Action").HtmlAttributes(new { @nowrap = "nowrap" });
})
.DetailView(childItems => childItems.Template(e =>
{
@Html.Telerik()
.Grid(e.ChildItems)
.Name("ChildItems")
.Columns(childColumns =>
{
childColumns.Bound(q => q.ServiceItemName).Title("Service Item Name")/*.ClientTemplate("<#= ServiceName #>")*/;
childColumns.Bound(q => q.Quantity).Title("Quantity")/*.ClientTemplate("<#= Quantity #>")*/;
childColumns.Bound(q => q.UnitPrice).Title("Unit Price")/*.ClientTemplate("<#= UnitPrice #>")*/;
childColumns.Bound(q => q.BookPrice).Title("Book Price")/*.ClientTemplate("<#= BookPrice #>")*/;
childColumns.Bound(q => q.ChildItemGuid).Hidden()/*.ClientTemplate("<#= ChildItemGuid #>")*/;
}
).Footer(false).Render();
})
)
.ClientEvents(events => events.OnRowDataBound("onRowDataBound"))
.RowAction(row =>
{
if (row.DataItem.ShowChildren == true)
row.DetailRow.Expanded = true;
}
).Render();
}
And the Editor template is as follows:
@model JWITS.UserManagement.Areas.TicketApproval.Models.ServicesItem
<script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>ServicesItem</legend>
<div id="msg"></div>
@if (Model.TicketGuid == default(Guid))
{
<div>
@Html.LabelFor(m => m.ServiceType, "Service Type")
@Html.DropDownList("ServiceTypes", string.Empty)
</div>
<div>
@Html.LabelFor(m => m.ServiceName, "Service")
@Html.DropDownList("Services", string.Empty)
</div>
}
@Html.HiddenFor(m => m.TicketGuid)
@Html.HiddenFor(m => m.LineItemId)
@Html.HiddenFor(m => m.ServiceGuid)
@Html.HiddenFor(m => m.RowIndex)
@Html.HiddenFor(m => m.PriceBookGuid)
<div>@Html.EditorFor(m => m.TicketGuid)</div>
<div class="editor-label">
@Html.LabelFor(m => m.ServiceName)
</div>
<div class="editor-field">
@Html.EditorFor(m => m.ServiceName, new { @size = 45 })
@Html.ValidationMessageFor(model => model.ServiceName)
</div>
<div class="editor-label">
@Html.LabelFor(m => m.CustomerPrice)
</div>
<div class="editor-field">
@Html.EditorFor(m => m.CustomerPrice)
@Html.ValidationMessageFor(model => model.CustomerPrice)
</div>
<div class="editor-label">
@Html.LabelFor(m => m.ServiceDiscount)
</div>
<div class="editor-field">
@Html.EditorFor(m => m.ServiceDiscount, new { @size = "8" })
@Html.ValidationMessageFor(model => model.ServiceDiscount)
</div>
<div class="editor-label">
@Html.LabelFor(m => m.ServiceType)
</div>
<div class="editor-field">
@Html.EditorFor(m => m.ServiceType, new { @size = "30" })
@Html.ValidationMessageFor(model => model.ServiceType)
</div>
<div class="editor-label">
@Html.LabelFor(m => m.BookPrice)
</div>
<div class="editor-field">
@Html.EditorFor(m => m.BookPrice, new { @size = "8" })
@Html.ValidationMessageFor(model => model.BookPrice)
</div>
<legend>ChildItems</legend>
<fieldset>
<table id="childitems">
<tr>
<th>ServiceItemName</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Book Price</th>
</tr>
@if (Model.ChildItems != null)
{
for (int i = 0; i < Model.ChildItems.Count; i++)
{
<tr>
<td>@Html.EditorFor(m => m.ChildItems[i].ServiceItemName) @Html.ValidationMessageFor(m => m.ChildItems[i].ServiceItemName)</td>
<td>@Html.EditorFor(m => m.ChildItems[i].Quantity) @Html.ValidationMessageFor(m => m.ChildItems[i].Quantity)</td>
<td> @Html.EditorFor(m => m.ChildItems[i].UnitPrice) @Html.ValidationMessageFor(m => m.ChildItems[i].UnitPrice)</td>
<td>@Html.EditorFor(m => m.ChildItems[i].BookPrice) @Html.ValidationMessageFor(m => m.ChildItems[i].BookPrice)</td>
</tr>
@Html.HiddenFor(m => m.ChildItems[i].AllowUnitPriceChange)
@Html.HiddenFor(m => m.ChildItems[i].AllowUnitsChange)
@Html.HiddenFor(m => m.ChildItems[i].ChildItemGuid)
@Html.HiddenFor(m => m.ChildItems[i].DisAllowDiscount)
@Html.HiddenFor(m => m.ChildItems[i].DisAllowUnitPriceChange)
@Html.HiddenFor(m => m.ChildItems[i].DisAllowUnitsChange)
@Html.HiddenFor(m => m.ChildItems[i].LineItemId)
@Html.HiddenFor(m => m.ChildItems[i].MinimumCost)
@Html.HiddenFor(m => m.ChildItems[i].MinimumUnits)
@Html.HiddenFor(m => m.ChildItems[i].NotDiscountable)
@Html.HiddenFor(m => m.ChildItems[i].ParentLineItemId)
@Html.HiddenFor(m => m.ChildItems[i].PriceBookGuid)
@Html.HiddenFor(m => m.ChildItems[i].Rule)
@Html.HiddenFor(m => m.ChildItems[i].SurCharge)
@Html.HiddenFor(m => m.ChildItems[i].Units)
@Html.HiddenFor(m => m.ChildItems[i].UnitsFree)
@Html.HiddenFor(m => m.ChildItems[i].WorkItemUnits)
@Html.HiddenFor(m => m.ChildItems[i].WorkType)
@Html.HiddenFor(m => m.ChildItems[i].TicketGuid)
}
}
else
{
<tr><td>No child items</td></tr>
}
</table>
</fieldset>
</fieldset>
}
Here is an abbreviation of the datamodel:
public class Ticket
{
public bool Deleted { get; set; }
public Guid ExportedByEmployeeGuid { get; set; }
public string TemplateName { get; set; }
public bool IsTemplate { get; set; }
public bool IsDefaultTemplate { get; set; }
public Guid EmployeeGuid { get; set; }
public string ContractNumber { get; set; }
public string CustomerNumber { get; set; }
public string CraneNumber { get; set; }
public string TruckNumber { get; set; }
public string FieldName { get; set; }
public string CasingSize { get; set; }
public string TubingSize { get; set; }
public string WellDeviation { get; set; }
public decimal NetBonusRevenue { get; set; }
public List<CrewMember> CrewMembers { get; set; }
public List<ServicesItem> ServicesItems { get; set; }
}
[KnownType(typeof(ServicesItem))]
[DisplayName("Service Item")]
public class ServicesItem
{
public Guid LineItemId { get; set; }
public Guid ServiceGuid { get; set; }
public string ServiceName { get; set; }
public decimal CustomerPrice { get; set; }
public int RowIndex { get; set; }
public Guid PriceBookGuid { get; set; }
public bool IsPerforating { get; set; }
public bool IsCustomItem { get; set; }
public Guid TicketGuid { get; set; }
public decimal ServiceDiscount { get; set; }
public string ServiceType { get; set; }
public string PriceBookName { get; set; }
public decimal BookPrice { get; set; }
public List<ChildItem> ChildItems { get; set; }
public bool ShowChildren { get; set; }
public bool IsDiscountable { get; set; }
public ServicesItem()
{
}
}
public class ChildItem
{
public Guid LineItemId { get; set; }
public Guid ChildItemGuid { get; set; }
public string ServiceItemName { get; set; }
public Guid ParentLineItemId { get; set; }
public int RowIndex { get; set; }
public string WorkType { get; set; }
public string WorkItemUnits { get; set; }
public Guid TicketGuid { get; set; }
public bool NotDiscountable { get; set; }
public string Units { get; set; }
public Guid PriceBookGuid { get; set; }
public bool DisAllowUnitPriceChange { get; set; }
public bool AllowUnitPriceChange { get; set; }
public bool AllowUnitsChange { get; set; }
public bool DisAllowUnitsChange { get; set; }
}
Now to my issue. For the Edit command button in the grid I have specified the action method as the partial view of that tab item, which is just the grid itself. This seems to work fine in that the popup will show the row item that was selected and I can edit it fine. But I notice that after I click the edit button on the grid for the row and the popup appears, the browser behind is only showing the partial view data from the tab item and is no longer showing the tab strip with the other tab items. This is not too much of an issue since I can redirect the action of the edit command back to the view with the tab strip when the edit action is complete and the entire view is shown rather than just the partial view for that tab item. I can also see how this makes sense in that when I click the Edit command on the grid row, MVC/Telerik is calling the partial view only and not the entire view containing the tab strip. But I really want the entire tab strip to repost from the server as before I clicked the Edit button on the grid row. Main reason being if the user clicks the cancel button on the popup all they are left with is the partial view and not tab strip. In noticing this I thought that since MVC/Telerik is only showing the partial view that I could change the action method for the edit commmand on the grid to the main view that contains the tab strip and all it's tab items and get the popup for the edit and the tab strip with all its items. This should show the entire view when posted back after clicking the edit command button. However when I change the action of the Edit command button to the entire view I get no popup for editing the row item but the entire view posts back with with tab strip and all its items as I want. I would suspect this has something to do with passing the data model to the partial view containing the grid in that tab and in the grid definition using the child item as the model for the grid. The grid only knows of the child items of the model and not the entire model but I do not know how to get around this issue.
Any help would be appreciated.