Kendo UI Grid MVC Not rendering - asp.net-mvc

I have recently started incorporating Kendo UI into my project. I have a strongly typed view and wish to bind the Kendo grid to the appropriate View Model on the view:
#ModelType IEnumerable(Of IMS_2.Models.expenseclaims)
#Code
ViewData("Title") = "Index"
End Code
<h2>Index</h2>
<div>
#code
Html.Kendo().Grid(Model).Name("ExpenseClaims") _
.Columns(Sub(c)
c.Bound(Function(x) x.ClaimDate).Width(140)
c.Bound(Function(x) x.Title).Width(190)
c.Bound(Function(x) x.Company)
End Sub)
end code
</div>
The code executes without exceptions on the server and with no javascript errors at the client. Examination of the rendered source shows no mention of the grid:
<h2>Index</h2>
<div>
</div>
<hr />
<footer>
...etc
My code is (I think) a direct translation of other examples I've seen in c# (see http://telerikhelper.net/2012/10/26/using-kendo-grid-in-asp-net-mvc-4-0/)
Expenseclaims is generated by the EF template and is defined as:
Partial Public Class expenseclaims
Public Property id As Long
Public Property Title As String
Public Property ClaimDate As Nullable(Of Date)
Public Property Creator As Nullable(Of Long)
Public Property Company As Long
Public Property AdvanceOffset As Nullable(Of Decimal)
Public Overridable Property expenselines As ICollection(Of expenselines) = New HashSet(Of expenselines)
Public Overridable Property companies As companies
End Class
The controller code is:
Public Class ExpenseController
Inherits System.Web.Mvc.Controller
Private db As New IMSEntities
' GET: /Expense/
Function Index() As ActionResult
Return View(db.expenseclaims.ToList())
End Function
Which is where I am stumped...Any help gratefully appreciated.

Edit: You do need the .tolist()
A really good vb start is at Telerik, at least that is where i started
http://docs.telerik.com/kendo-ui/getting-started/using-kendo-with/aspnet-mvc/vb
I did mine a bit different but this should get same result for you. I think possibly the issue is you are wrapping this is a code block which isn't really right from what I read. Here is an example of what I do for a tracking grid.
Where I have the datasource(since I use an ajax source and you want to use a model) you can just put the following:
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.ServerOperation(false)
)
The bottom line is that you seem to be missing the datasource and I am unsure about the code block to be honest, but I do not do it that way.
#(Html.Kendo().Grid(Of TrackingGroupModel)().Name("grid") _
.Columns(Function(col)
col.Bound(Function(e) e.TrackingNumber).ClientTemplate("<a href='#=ShippingCompanyUrl##=TrackingNumber#' target='_blank'>#=TrackingNumber#</a>")
col.Bound(Function(e) e.DateAdded).Format("{0:D}")
col.Bound(Function(e) e.ProductCount).Title("Total Shipped")
col.Command(Function(command) command.[Custom]("View Details").Click("showDetails"))
End Function)
.DataSource(Function(ds) ds.Ajax().Read(Function(read) read.Action("getTracking", "OrderManagement", New With {.id = Model.Id})))
)

Related

Rendering custom sections of an ASP.NET MVC EditorFor

I am late in on a project where possibly the most important requirements have been ignored until the 11th hour.
The application allows suppliers to apply to become contractors for a company via a fairly in depth online application form.
The application takes the form of question sections that make up a left sidebar nav and each section has a number of questions.
The requirements that have been ignored up until now are that each applicant who fills out a form online has an application type, e.g. construction, catering etc. and the requirements state that the application is configurable so that only certain sections appear to a certain application type and certain questions within a section should be configurable to appear to a particular application type.
Configuring the sections is easy but configuring the questions is not so easy. At the moment everything is hardcoded into razor views and EditorFor templates. Basically there is one EditorFor per ViewModel which makes up a Section e.g.
#model Models.Enforcement
<div >
<form class="form-horizontal" method="post" action="#Url.Action(nameof(ApplicationController.Enforcements))"
#Html.EditorFor(x => x)
</div>
And the editor for will look something like this:
#model GSCM.Logic.Web.Models.Enforcement
#using System.Web.Mvc.Html
<div>
#Html.HiddenFor(x => x.Id)
<div class="form-group">
#Html.LabelFor(model => model.Name)
<div>
#Html.TextBoxFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
My solution to this problem is to first of all be able to add custom attributes to a ViewModel class that tag the property as a configurable Question, e.g.
public class Enforcement
{
[ApplicationQuestion DisplayOrder=1, Partial="DifferentNamedPartial"]
public string Name{get;set;}
}
I then have my own EditorFor that loops through all these tagged Properties:
using System.Web.Mvc.Html;
public static class HtmlHelperExtensions
{
public static MvcHtmlString QuestionSetEditorFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, VMBaseClass model)
{
//PSEUDO CODE
var sectionHtml;
ForEach(var taggedProperty in model)
{
var basedOnProperty = GetFilePathFromProperty(taggedProperty);
sectionHtml += System.Web.Mvc.Html.GetPartial(basedOnProperty)
}
return MvcHtmlString.Create(sectionHtml);
}
}
So basically, I would need to chop up the existing EditorFor ViewModel templates and have a partial for each section, property.
My questions are:
Is this a good idea or is there a better way. Time is a constraint (as always)?
Can I create the html string in the way I have outlined above with the pseduo code that loops rounds the properties and calls out to the partials?
Here you can proceed like
Suppose your partial pages which you want to call in main pages using loops are:
_form-one-partial.cshtml
_form-two-partial.cshtml
_form-three-partial.cshtml
_form-four-partial.cshtml
_form-five-partial.cshtml
One of those partial page content as:
#model PartialFieldViewModel
//---other fileds on the page
<input type="text"/>
//---other fileds on the page
To call the partial on the basis of the loop around the "partial" varible in the main page where partial will be called as:
#model PartialViewModel
foreach (var partial in Model.Parital)
{
#Html.Partial("_form-{0}-partial".FormatWith(partial.PartialType.ToString().ToLower()), partial)
}
Partial view modal class as
public class PartialViewModel
{
//Other properties
public List<PartialFieldViewModel> Partial { get; set; }
}
public class PartialFieldViewModel
{
//Other properties
public Constants.PartialType PartialType{ get; set; }
}

MVC not passing model data from view to controller

This is a very basic model/view/controller and the model is not coming from the view with any data to the controller. It is probably something basic that I am missing!
Two Models:
Namespace Models
Public Class Search
Public Property Search() As String = String.Empty
Public Property Member() As Member = Nothing
End Class
End Namespace
Namespace Models
Public Class Member
Public Property ContactRefID() As String = String.Empty
End Class
End Namespace
Controller:
Imports Test.Models
Imports Test.Services
Namespace Test
Public Class HomeController
Inherits System.Web.Mvc.Controller
Function Index() As ActionResult
Dim search As New Search
Return View("Index", search)
End Function
<HttpPost()>
Function Index(ByVal search As Search) As ActionResult
Dim member As New Member
Dim homeRepository As New HomeRepository
member = homeRepository.GetMemberData(search)
search.Member = member
Return View("Index", search)
End Function
End Class
End Namespace
View:
#ModelType Test.Models.Search
#Code
ViewData("Title") = "Search Page"
End Code
#Using Html.BeginForm("Index", "Home", FormMethod.Post)
#<div class="row">
<div class="col-md-4">
<label>Search Member/Account Number:</label>
#Html.TextBoxFor(Function(model) model.Search)
<br /><br />
<button id="btnSubmit" type="submit" class="btn btn-primary btn-large clrButton">
Search
</button>
</div>
</div>
<div class="row">
#*...To be filled with Search.Member data*#
</div>
End Using
When I enter a member/account number in the textbox to initiate the search, the search value does not get sent to the 2nd Index function in the controller. It definitely gets called because my breakpoint inside of it gets hit, but the "ByVal search As Search" comes back as Nothing.
I know in 2013 that the get:set items are not needed for the Models, but I tried to add them and it still didn't work.
I also set a value for search.Search in the top index and the textbox gets populated with the value. But when I click the Search button, it doesn't get sent to the 2nd index function either.
Any suggestions?
DefaultModelBinder is unable to bind/recognize a property if the type has the same name - in this case Search. Just change the property to something else and you're good to go...
Generally it's a good practice to think through the objects you're going to create and avoid such tautology. It will be easier for you to maintain these objects if they sounds reasonable. E.g. in this case, you use the name Search for your class. There is no sense to name the sought value Search too. Just name it as it should - SoughtValue

ASP.NET MVC Model Binding horror

I have two nearly identical scenarios regarding model binding on a controller action. One works, and one doesn't. I can't figure out why.
This works:
Given this ViewModel class:
Public Class SeasonCreateViewModel
Public Property Season As Season
End Class
We have these actions
Function Create() As ActionResult
Dim seasonVM As New SeasonCreateViewModel()
Return View("Create", seasonVM)
End Function
<HttpPost()>
<ValidateAntiForgeryToken()>
Function Create(seasonVM As SeasonCreateViewModel) As ActionResult
End Function
And everything binds perfectly. seasonVM.Season contains the values posted from the form.
HOWEVER, this doesn't work:
Given this ViewModel class:
Public Class UserCreateViewModel
Public UserPerson As UserPersonModel
End Class
And these actions:
Function Create() As ActionResult
Dim userVM As New UserCreateViewModel()
Return View("Create", userVM)
End Function
'
' POST: /Admin/User/Create
<HttpPost()>
<ValidateAntiForgeryToken()>
Function Create(userVM As UserCreateViewModel) As ActionResult
End Function
userVM.UserPerson does not bind to the form values the same way seasonVM.Season does. In fact, it is Nothing (aka. null)
Does anyone have any ideas?
If you're curious about the views, they are structured identically, as in:
#Using Html.BeginForm()
#Html.AntiForgeryToken()
#Html.ValidationSummary(True)
<div class="editor-label">
#Html.LabelFor(Function(model) model.UserPerson.NewUsername)
</div>
<div class="editor-field">
#Html.EditorFor(Function(model) model.UserPerson.NewUsername)
#Html.ValidationMessageFor(Function(model) model.UserPerson.NewUsername)
</div>
<p>
<input type="submit" value="Create" />
</p>
End Using
AND
#Using Html.BeginForm()
#Html.AntiForgeryToken()
#Html.ValidationSummary(True)
<div class="editor-label">
#Html.LabelFor(Function(model) model.Season.SeasonDescription)
</div>
<div class="editor-field">
#Html.EditorFor(Function(model) model.Season.SeasonDescription)
#Html.ValidationMessageFor(Function(model) model.Season.SeasonDescription)
</div>
<p>
<input type="submit" value="Create" />
</p>
End Using
Just a note: I've omitted irrelevant code, mostly just additional properties on the view pages. I will say there is no property named "userVM" on my UserPersonModel as was the case here: Model is null when form submitted
UPDATE
OK. I think I'm about ready to give up on figuring out why Season is binding properly, but UserPerson is not.
I thought I had figured out the answer, but it didn't seem to actually make a difference:
I have
Public Class SeasonCreateViewModel
Public Property Season As Season
End Class
and I have
Public Class UserCreateViewModel
Public UserPerson As UserPersonModel
End Class
When lined up like this, the difference seems obvious. In SeasonCreateViewModel, I have a property Season identically named to the class it is an instance of (Season). In UserCreateViewModel, I have a property UserPerson, which is named slightly differently from its class UserPersonModel. Because of this, I thought the model binder does not automatically match userVM.UserPerson to its corresponding class.
So I changed the class UserPersonModel to UserPerson so the Form values would match up in the same way they do for Season (ie, to the classname), but it STILL did not fix it.
What does fix it, however, is if I change this:
Function Create(userVM As UserCreateViewModel) As ActionResult
to this
Function Create(userPerson As UserPerson) As ActionResult
Why this suddenly binds properly, where it didn't before? I have no idea. Does this help anyone answer this question, though?
As I understand it, you are not creating a new instance of UserPersonModel. I could be very wrong though :)
Public Class UserCreateViewModel
Public UserPerson As UserPersonModel
End Class
I think in your action, you should do something like:
Function Create() As ActionResult
Dim userVM As New UserCreateViewModel()
//userVM.UserPerson = new UserPersonModel() -- in c#
//userVM.UserPerson As New UserPersonModel() -- in VB?
Return View("Create", userVM)
End Function
Or just ignore this answer :P
I've ran into this before and the answer is not at all obvious, but makes sense after you know. If you bind an entire model (rather than a static type), then every single member of that model must be posted in the form, otherwise, the modelbinder doesn't recognize the posted values as an instance of the model.
If you don't want to post every member, but rather just a subset, then you need to create a view model with just the fields you want to post, and use something like AutoMapper or just manually map the fields on the actual model in your POST action.

httppost returns nothing with complex objects in mvc3 razor vb.net

I'm having issues with my MVC3 vb.net application. When I try to post the changes I've made to the controller, the model is not send to the controller.
I've tried to follow many posts like this one and this one, but I'm not sure of how to implement them in my application since my model did not send IEnumerable types.
At the end I only want that the model returns one value for each batch that is the value that I will save to the database.
When I post the model and try to send to the controller the page sends the following by post:
Client=2&Datacenters=20&BatchesForAssignation[0].CenterID=4&BatchesForAssignation[1].CenterID=20&BatchesForAssignation[1].DatacenterID=14...
But I don't know how to convert this querystring to a BatchesForAssignation object, assign it to the model and send to the controller.
NOTE: The values for Client and Datacenters shown in the querystring are not used in the controller. I need the BatchesForAssignation[n].CenterID part.
Can you please point me to found a solution on this?
This are the objects that I'm using in my MVC application (code compacted):
Batch:
Public class Batch
public property ID as integer
public property CenterID as integer
public property name as string
end class
Centers (This object just store all the list of centers that will be assigned to the Batch. The name is just to show the name in the drop down list):
Public class Center
public property ID as integer
public property name as string
end class
(There's also a Batchlist and a Centerlist objects that acts as collections inherited from CollectionBase that stores all the Batch and Center objects. If you need the class definition please let me know but is pretty strightforward).
The model is as follows
Public class ProcessingModel
public property BatchesForAssignation as BatchList
public property Datacenters as CenterList
End class
The Controller is as follows:
<HttpGet()>
<Authorize()> _
Public Function AssignToDataCenters() As ActionResult
Dim model As New ProcessingModel
Dim BatchHandler As New BatchControl
'This line will get the list of batches without datacenter
model.BatchesForAssignation = BatchHandler.GetBatchesAvailable(ConnectionString)
'This method will get the list of Datacenters available
model.Datacenters=BatchHandler.GetDatacenters(ConnectionString)
return View(model)
End Function
HttpPost (This is actually not working because the model returns an empty model):
<HttpPost()>
<Authorize()> _
Public Function AssignToDataCenters(ByVal Model as ProcessingModel) As ActionResult
Dim BatchHandler As New BatchControl
Dim SaveResult as Boolean=false
'This line will get the list of batches without datacenter
model.BatchesForAssignation = BatchHandler.GetBatchesAvailable(ConnectionString)
'This method save the information returned by the model
SaveResult=BatchHandler.UpdateBatches(model)
ViewBag("Result")=SaveResult
Return View(model)
End Function
The View is as follows (is a Strongly-typed view):
#ModelType MVCAdmin.ProcessingModel
#Code
ViewData("Title") = "Assign Batches To centers"
End Code
#Using Html.BeginForm()
#<table id="tblAvailableBatches">
<thead>
<tr>
<th>Assign batch to:</th>
<th>Name</th>
</tr>
</thead>
<tbody>
#code
For i As Integer = 0 To Model.BatchesForAssignation.Count - 1
Dim a As Integer = i
#<tr>
<td>#Html.DropDownListFor(Function(m) m.BatchesForAssignation(a).CenterID, New SelectList(Model.Datacenters, "ID", "name", model.BatchesForAssignation(i).CenterID), " ")</td>
<td>#Model.BatchesForAssignation(i).name</td>
</tr>
Next
End Code
</tbody>
</table>
<input type="button" value="Apply changes" id="btnApply" />
End Using
Thanks in advance
UPDATE 2012-06-14:
After making some researh I found that I can parse the querystring in the controller using request.Form I can parse the results sent by the view. But the querystring keys are in the form BatchesForAssignation[0].CenterID,BatchesForAssignation[1].CenterID,BatchesForAssignation[2].CenterID and so on...
Is there's a better way to do this "automagically" so that the model parses the querystring and sends the parsed object to the controller?
Again...Thanks in advance
After reviewing this question I've found that the best way to create the model and send it to the controller is creating a CustomModelBinder (from the IModelBinder Interface) and parsing the form's querystring on the BindModel method using the controllerContext.HttpContext.Request.Form property. Something like this:
Public Class ProcessingModelBinder
implements IModelBinder
public Function BindModel(controllerContext As System.Web.Mvc.ControllerContext, bindingContext As System.Web.Mvc.ModelBindingContext) As Object
dim model as ProcessingModel = if(nothing.equals(bindingContext.Model),directcast(bindingContext.Model,directcast(DependencyResolver.Current.GetService(typeof(ProcessingModel))
dim Keys as string()=controllerContext.HttpContext.Request.Form.AllKeys
for each key in Keys
'Fill the model required parameters
Next
return model
End Function
And finally register the new Model Builder in the global.asax file
Sub Application_Start()
AreaRegistration.RegisterAllAreas()
ModelBinders.Binders.Add(typeof(ProcessingModel),New ProcessingModelBinder())
RegisterGlobalFilters(GlobalFilters.Filters)
RegisterRoutes(RouteTable.Routes)
End Sub
I hope that this helps someone
Regards

Binding, Prefixes and generated HTML

MVC newbie question re binders. Supposing I have two strongly typed partial actions that happen to have a model attributes with the same name, and are rendered in the same containing page i.e.:
Class Friend {string Name {get; set ;} DateTime DOB {get; set ;}}
Class Foe {string Name {get; set ;} string ReasonForDislike {get; set ;}}
Both partials will have a line:
<%= Html.TextBoxFor(model => model.Name) %>
And associated controller actions:
public ActionResult SaveFriend(Friend friend)
public ActionResult SaveFoe(Foe foe)
My problem is that both will render on my containing page with the same id (of course, bad for lots of reasons). I’m aware of the [Bind] attribute that allows me add a prefix, resulting in code:
public ActionResult SaveFriend([Bind(Prefix = “friend”)] Friend friend)
<%= Html.TextBox("friend.Name", Model. Name) %> //Boo, no TextBoxFor :(
But this still doesn’t cut it. I can just about tolerate the loss of the strongly typed TextBoxFor helpers but I’ve yet to get clientside validation to work with prefixes:
I’ve tried:
<%= Html.ValidationMessage("friend.Name") %>
...and every other variant I can think of.
I seem to need the model to be aware of the prefix in both directions but bind only applies when mapping the inbound request. It seems (to me) a common scenario but I’m struggling to find examples out there. What am I missing!
Thanks in advance.
The prefix is there so you can wrap your objects in an "outer" ViewModel.
Suppose we have:
public class MyViewModel
{
public Friend friend;
public Foe foe;
}
If you use this class as your ViewModel and as the base of your strongly-typed Views, then your strongly-typed Textboxes will be named thusly:
friend.Name
foe.Name
You can then use the Prefix attribute you refer to in your question to disambiguate between your Friend and Foe classes.

Resources