Sorting with MVCContrib - asp.net-mvc

Does anyone know how to sort the MVCContrib grid when using a complex object.
My grid is displaying a list of Person and I'm trying to sort on the Country property. The problem is that Country is a property an Address class which is a property of Person.
Person.Address.Country
<%Html.Grid(Model).Columns(column =>
{
column.For(x => x.Id);
column.For(x => x.FirstName);
column.For(x => x.LastName).Sortable(false);
column.For(x => x.Address.Country).Sortable(false);
column.For(x => x.Age).Sortable(true);
}).Render(); %>
Exception:
Property 'Country' is not defined for type '{Namespace}.Person'
var sourceProp = Expression.Property(sourceParam, this.SortBy);
\MVCContrib\UI\Grid\Sortable\ComparableSortList.cs Line: 41
Any suggestions would be helpful.
Thank you,
MG1

A workaround would be to expose Country as a property on Person and use that:
public string Country { get { return Address.Country; } }

#orip gave you an answer.
But if you want to use the sorting feature you need to use:
<%Html.Grid(Model).Columns(column =>
{
column.For(x => x.Id);
column.For(x => x.FirstName);
column.For(x => x.LastName).Sortable(false);
column.For(x => x.Address.Country).Sortable(false);
column.For(x => x.Age).Sortable(true);
}).RenderUsing(new SortableHtmlTableGridRenderer<Person>())
.Render(); %>
Source: http://www.jeremyskinner.co.uk/2009/02/23/rewriting-the-mvccontrib-grid-part-3-gridmodels-and-gridrenderers/

You need to use SortColumnName for this.
column.For(x => x.Address.Country).SortColumnName("Address.Country");
I have tested this and it works like a charm :)
If you are not able to access SortColumnName(), you can get the latest version of MVC contrib from
http://mvccontrib.codeplex.com/SourceControl/changeset/changes/7db1cecc938f

Related

How to Apply Class to GridMVC

I need to apply some masking class to some columns.
Razor
#Html.Grid(Model).Columns(columns =>
{
columns.Add(c => c.BrokerID).Titled("FEN Account ID").SetWidth(220);
}
Exm :
Html.Grid(x).Columns(col => {}).Attributes(#class => "usertable");
You can just use the Css method to add a class to a column:
Columns.Add(x => x.Number).Css("hidden-xs")

Kendo UI Grid pass value to edit popup

I'm using Kendo UI MVC and I have a view that contains details about an object. On that page I have a Kendo UI Grid that shows a list of notes about the object. I allow the user to create or edit the notes from the grid.
The problem I have is when the user clicks the add button I need to pass the id of the page's object. I'm using GridEditMode.PopUp.
Basically, this is what I have:
public class Item {
public int Id { get;set; }
...
}
public class Note {
public int ItemId {get;set;}
...
}
Here is the grid code:
#(Html.Kendo()
.Grid<NoteViewModel>()
.Name("kendo-grid")
.Columns(columns =>
{
columns.Bound(n => n.NoteDateTime).Title("Date").Format("{0:MM/dd/yyyy}");
columns.Bound(n => n.NoteDateTime).Title("Time").Format("{0:h:mm tt}").Sortable(false);
columns.Bound(n => n.NoteActivityType).Title("Activity Type");
columns.Bound(n => n.NoteDescription).Title("Description");
columns.Bound(n => n.NoteDetail).Title("Notes");
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(200);
})
.ToolBar(toolbar => toolbar.Create())
.Editable(editable => editable.Mode(GridEditMode.PopUp).TemplateName("Note"))
.Mobile()
.Pageable()
.Sortable()
.Filterable()
.Reorderable(r => r.Columns(true))
.Resizable(r => r.Columns(true))
.DataSource(dataSource => dataSource.Ajax()
.Model(model => model.Id(note => note.Id))
.PageSize(25)
.Sort(sort =>
{
sort.Add(note => note.NoteDateTime);
})
.Read(read => read.Action("ReadNotes", "Case").Data("getCaseId"))
.Create(a => a.Action("CreateNote", "Case"))
.Update(u => u.Action("UpdateNote", "Case"))
.Destroy(d => d.Action("DeleteNote", "Case"))
)
)
I need to set Note.ItemId when the user clicks the add button on the grid. Or, is there a better way to do this, as in send the ItemId value on the post?
I ended up getting this to work by hooking into the edit event of the popup. I wasn't able to figure out how to do it on the initial setup, so I added this to doc ready handler to the edit popup. This kind of feels like a hack, so if someone has a better way I'd love to hear about it. The #ItemId input is already on the details page, so I figured I may as well use it.
$(function () {
function setItemId(event) {
var uid = $('.k-edit-form-container').closest('[data-role=window]').data('uid');
var model = $('#kendo-grid').data('kendoGrid').dataSource.getByUid(uid);
if (model.get('ItemId') === 0) {
model.set('ItemId', Number($('#ItemId').val()));
}
}
var grid = $('#kendo-grid').data('kendoGrid');
grid.bind('edit', setItemId);
});
I'm not sure if it's possible what you want, but to get you on the way this is how you'd start doing it.
You generally want a flat viewmodel, containing everything you want to use.
public class NoteViewModel {
public int ItemId { get;set; }
}
Then properly setup the use of your editor template. Since your ItemId is now part of the grid's model it'll be send to the controller on edit/create.
#(Html.Kendo()
.Grid<NoteViewModel>()
.Name("kendo-grid")
.Columns(columns =>
{
columns.Bound(n => n.ItemId).Hidden();
columns.Bound(n => n.NoteDateTime).Title("Date").Format("{0:MM/dd/yyyy}");
columns.Bound(n => n.NoteDateTime).Title("Time").Format("{0:h:mm tt}").Sortable(false);
columns.Bound(n => n.NoteActivityType).Title("Activity Type");
columns.Bound(n => n.NoteDescription).Title("Description");
columns.Bound(n => n.NoteDetail).Title("Notes");
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(200);
})
.ToolBar(toolbar => toolbar.Create())
.Editable(editable => editable.Mode(GridEditMode.PopUp).TemplateName("NoteTemplate"))
Etc...
)
Finally create your template (called NoteTemplate.cshtml) and place it in Views/Shared/EditorTemplates so Kendo can find it.
#model NoteViewModel
Date: #Html.EditorFor(l => l.NoteDateTime)
Note Description: #Html.EditorFor(l => l.NoteDescription)
(Add all fields you need to edit here)
I had same problem
Problem is that some of fields of the model(viewmodel) is nullable
Model nullable field is not fully supported in Kendo UI

KendoUI Edit Issue

Kendo UI edit option showing some unexpected behaviour, as you can see in the image there is a text box below Server column and 2 below ServerIP column all containing the id of server "SQL" i selected. Problem is when ever i want to show Server IP column this behaviour occurs, both server and server IP are from the same table.
#(Html.Kendo().Grid<EnvironmentPOCO>()
.Name("Grid")
.Columns(columns =>
{
columns.Bound(d => d.EnvironmentName).Width(200).Title("EnvirontmentName");
columns.ForeignKey(d => d.EnvironmentTypeID, (List<EnvironmentTypePOCO>)ViewData["EnvironmentType"], "EnvironmentTypeID", "EnvironmentTypeCode").Width(150).Title("EnvironmentCode").EditorTemplateName("_EnvironmentCodeDropDown");
columns.ForeignKey(d => d.ServerID, (List<ServerPOCO>)ViewData["ServerDetails"], "ServerID", "ServerName").Width(200).Title("Server").EditorTemplateName("_ServerDropDown");
columns.ForeignKey(d => d.ServerID, (List<ServerPOCO>)ViewData["ServerDetails"], "ServerID", "ServerIP").Width(200).Title("ServerIP");
columns.ForeignKey(d => d.ProjectID, (List<ProjectPOCO>)ViewData["Projects"], "ProjectID", "ProjectName").Width(200).Title("ProjectName").EditorTemplateName("_ProjectNameDropDown");
// columns.ForeignKey(d => d.ProjectID, (List<ProjectPOCO>)ViewData["Projects"], "ProjectID", "ProjectDescription").Width(200).Title("ProjectDescription")/*.EditorTemplateName("_ProjectDescription")*/;
columns.Command(d =>
{
d.Edit();
d.Destroy();
}).Width(200).Title("Action");
})
.ToolBar(tools => tools.Create())
.Sortable()
.Pageable()
.Filterable()
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
model.Id(m => m.EnvironmentID);
model.Field(m => m.EnvironmentName);
model.Field(m => m.EnvironmentTypeID);
model.Field(m => m.ProjectID);
model.Field(m => m.ServerID);
})
.Read(read => read.Url(ViewBag.ApiBaseUrl).Type(HttpVerbs.Get))
.Create(create => create.Url(ViewBag.ApiBaseUrl).Type(HttpVerbs.Post))
.Update(update => update.Url(ViewBag.ApiBaseUrl).Type(HttpVerbs.Put))
.Destroy(destroy => destroy.Url(ViewBag.ApiBaseUrl).Type(HttpVerbs.Delete))
)
)
I found a solution to this, actually if you want to show 2 fields of the foriegn key, You can make a property in your class.
public string ServerDetailsProperty
{
get
{
return string.Format(" Name: {0} || IP: {1}", ServerName, ServerIP);
}
}
then call it in your csHTML file like this.
columns.ForeignKey(d => d.ServerID, (List<ServerPOCO>)ViewData["ServerDetails"], "ServerID", "**ServerDetailsProperty**").Width(200).Title("ServerIP");
Now if you press Edit you want see the unexpected behiour as in the diagram.
Try Changing the id and name attribute of the Server IP columns as the Grid is not able to differentiate between the Server Column and Server IP column on Edit.
For your reference I have tried below:
columns.ForeignKey(d => d.ServerID, (List<ServerPOCO>)ViewData["ServerDetails"], "ServerID", "ServerIP").Width(200).Title("ServerIP").HtmlAttributes(new { #id="ServerIP_#=ServerIP#", #name="ServerIP_#=ServerIP#" })
Let me know if this doesn't solve your issue.
EDIT:
You can add the dropdown in client template as below:
columns.Bound(s => s.ServerID).ClientTemplate((#Html.Kendo().DropDownList()
.BindTo((List<ServerPOCO>)ViewData["ServerDetails"])
.Name("ServerIP#=ServerIP#")
.DataTextField("ServerIP")
.DataValueField("ServerID")
.ToClientTemplate()).ToHtmlString());
On Grid DataBound event set the grid scripts to load with document as below:
function onGridDataBound(e) {
$('#GridName script').appendTo(document.body);
}
Finally set the field to readonly in model meta:
model.Field(s => s.SensorID).Editable(false);
For further information have a look at the explaination: Dropdown in Column Client Template

Get UNIX_TIMESTAMP in a query at CakePHP2

I am trying to get this calculate field, UNIX_TIMESTAMP, or as CakePHP calls them, "virtualField".
I have tried this but it didn't work. At my model:
public $virtualFields = array('unixDate' => 'UNIX_TIMESTAMP(Comment.created)');
public function index($idPost){
$comments = $this->Comment->find('all', array(
'conditions'=> array('Comment.idPost' => $idPost),
'order' => 'Comment.id DESC'),
'fields' => array('unixDate'));
}
What am I doing wrong?
Thanks.

MvcContrib Grid for editing only some columns

I Have a view:
<% Html.Grid(Model.InnerModel.OrderRecords)
.Empty("No data available")
.Attributes(new Hash(id => "RoadReportResultsTable"))
.Columns(column =>
{
column.For(x => x.OrderNumber);
column.For(x => x.DateReceived);
column.For(x => x.TotalCount);
column.For(x => x.DateSent);
column.For(x => x.SentCount);
column.For(x => x.Comments);
}).Render();
%>
I need to make only the Comments column editable, so the user can only enter the Comments, but can't edit any of the other columns.
I want to open a popup on Comments Click
On my project I use this code to add action link to column:
column.For(group => Html.ActionLink("Delete", "Delete", new { appId = Model.ApplicationId, id = group.Id }, null))
.Encode(false)
.Sortable(false);

Resources