Issue with EditorTemplates - c#

ASP.Net MVC 4.0 based Scenario:
I need to render a set of Widgets[aka User Control with sets of custom fields] on a screen.
The ViewModel for this Widget is something like this -
Public Class Widget
{
public string Header {get;set;}
//Note the data type here. It causes issues with rendering Widget itself.
public object ActualContent {get;set;}
public string Footer {get;set;}
}
At, run-time, say I want to render 2 widgets. Then all I need to do is create the instances as shown below :
Widget w1 = new Widget()
{
Header ="PatientDetails",
ActualContent = new Patient ()
{
FirstName = "ABC",
LastName = "XYZ"
}
Footer = "PatientDetails
};
Widget w2 = new Widget()
{
Header ="Address-Header",
ActualContent = new Address ()
{
ZIPCode = "123456",
Extn = "1234"
}
Footer = "Address-Footer"
};
The cshtmls are :
Main Page i.e Widget.cshtml
#using Widgets.Models
#model List<Widget>
...
<div class="widget">
<div class="header">
#Model.Header
</div>
<div class="body" >
#Html.EditorFor(model => Model.ActualContent)
</div>
<div class="footer">
#Model.Footer
</div>
</div>
...
Patient.cshtml in ~\Views\Shared\EditorTemplates
#model Widgets.Models.Patient
<div class="editor-label">
#Html.LabelFor(model => Model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.FirstName)
#Html.ValidationMessageFor(model => Model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => Model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.LastName)
#Html.ValidationMessageFor(model => Model.LastName)
</div>
Address.cshtml has a similar implementation.
Note, the property ActualContent, is of type object. It can be assigned an instance of any UserControl [Patient,Address,etc] at runtime.
Also, each of the UserControls has a corresponding strongly typed cshtml view defined inside the EditorTemplates.
Issue :
Now the issue is when I try to load the Widgets, I can see both the widgets getting rendered but only displaying the Header & Footer values.
The portion correponding to the ActualContent property, as shown above is not rendered at all, despite the fact that, while debigging, I can see that
corresponding .cshtml for Patients & Address are getting accessed!
I feel there might be something that I may have missed out on.
It would be nice if someone can get this working for me. Thanks in advance.
Sandesh L.

Try to access your Editor template like this,
#Html.EditorFor(m => m.ActualContent, "_YourEditorTemplate")

Related

How to Combine 2 textbox data in 1 textbox in MVC5

I have a MVC5 project, I have First Name and Last Name as 2 separate textboxes. I need to combine these 2 and shows as one textbox as Customer Name how I can do that?
This is what I have now that shows 2 text boxes:
<div class="form-group">
#Html.LabelFor(model => model.First_Name, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.First_Name, new{disabled = "disabled" })
#Html.ValidationMessageFor(model => model.First_Name)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Last_Name, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.Last_Name, new{disabled = "disabled" })
#Html.ValidationMessageFor(model => model.Last_Name)
</div>
</div>
If the fields are truly combined then you'd add a property to your model representing the new single field:
public string CustomerName { get; set; }
and use it in your view:
#Html.TextBoxFor(model => model.CustomerName, new{disabled = "disabled" })
#Html.ValidationMessageFor(model => model.CustomerName)
(Though if, when saving back to the server, you need to parse the values back out into two separate fields then that can get tricky. Don't make too many assumptions about names. But if you must, then that parsing should likely happen in the setter for this property and the getter should dynamically display the concatenated values as below.)
If, on the other hand, it should be a read-only display of the combined values, you'd create a read-only property to view the other values:
public string CustomerName
{
get { return string.Format("{0} {1}", First_Name, Last_Name); }
}
and you can simply display it in the view:
#Html.DisplayFor(model => model.CustomerName)
or just bind directly to the value in your own markup:
<span>#Model.CustomerName</span>
(In this approach you might also write some JavaScript to update the client-side displayed value as the values in the other fields change.)
It really depends on what you want to do with this field, if it saves back to the model or is only for display purposes.

Passing a model through a Partial View MVC3

I have a Partial View that goes like this:
#model IEnumerable<NutricionApp.Models.Ingrediente>
<table>
<tr>
<th>
NombreIngrediente
</th>
<th>
CantidadPorPorcion
</th>
<th>
UnidadPorPorcion
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.NombreIngrediente)
</td>
<td>
#Html.DisplayFor(modelItem => item.CantidadPorPorcion)
</td>
<td>
#Html.DisplayFor(modelItem => item.UnidadPorPorcion)
</td>
</tr>
}
</table>
I want to render said partial view in this View, that is strongly typed:
#model NutricionApp.Models.Platillo
#{
ViewBag.Title = "Create";
Model.ListadeIngredientes = new List<NutricionApp.Models.ListaIngredientes>();
}
<h2>Create</h2>
<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>Platillo</legend>
<div class="editor-label">
#Html.LabelFor(model => model.NombrePlatillo)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.NombrePlatillo)
#Html.ValidationMessageFor(model => model.NombrePlatillo)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.idRestaurante)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.idRestaurante)
#Html.ValidationMessageFor(model => model.idRestaurante)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DescripcionPlatillo)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.DescripcionPlatillo)
#Html.ValidationMessageFor(model => model.DescripcionPlatillo)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.esAprobado)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.esAprobado)
#Html.ValidationMessageFor(model => model.esAprobado)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.esDisponible)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.esDisponible)
#Html.ValidationMessageFor(model => model.esDisponible)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.precio)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.precio)
#Html.ValidationMessageFor(model => model.precio)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.VigenciaPlatillo)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.VigenciaPlatillo)
#Html.ValidationMessageFor(model => model.VigenciaPlatillo)
</div>
<!--<table>
<tr><th>Nombre</th></tr>
##foreach (var item in (List<NutricionApp.Models.ListaIngredientes>)Session["Lista"])
{
<tr>
<p>
<td>##item.ingrediente.NombreIngrediente</td>
</p>
</tr>
}
</table>-->
#Html.Partial("_Ingredientes", Model.);
<br />
#Html.Partial("_ListaIngredientes", Model.ListadeIngredientes)
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
And in my controller I have this:
//....
public ActionResult _ListaIngredientes()
{
IEnumerable<ListaIngredientes> ListaDemo = new List<ListaIngredientes>();
return View(ListaDemo);
}
public ActionResult _Ingredientes()
{
return View(db.Ingredientes.ToList());
}
In this case, db.Ingredients.ToList()); returns the data i need to show on the partial view. Problem is, when I try to display said list in my view, it tells me I have to pass a IEnumerable model corresponding to my view...
If I access the PartialView from an URL, it shows me the data correctly. However if i try to do this from inside a View, it passes the Model it's currently using due to being strongly-typed. How can I pass the model i need (the list of my ingredients table, db.Ingredientes.ToList());
You can reference the parent view's model from the partial view so perhaps package it all together in the top level view. You can also pass the model down explicitly (or whatever you want) via the Html.Partial overload. If you decide to access the model from the View make sure you include the #model directive in both View and PartialView.
Your view is expecting a IEnumerable of a model (NutricionApp.Models.Ingrediente). You are passing it an IEnumerable of an entity (ListaIngredientes). That's why it's barfing.
Assuming that the constructor of your Ingrediente model accepts a ListaIngredientes as a parameter, you can change this line:
#Html.Partial("_ListaIngredientes", Model.ListadeIngredientes)
to
#Html.Partial("_ListaIngredientes", Model.ListadeIngredientes.Select(i => new Ingrediente(i)))
which should fix your problem.
Are you trying to render dynamic partial view based on data passed to parent view? if yes, use Html.RenderAction() method and do some modification on your controller so that it returns a different data every time it's called and returns the partial view to parent view.
Assuming that there the Platillo and ingredient entities are related with one to many relation,
you could try something like this:
In parent view:
#{ Html.RenderAction("_Ingredientes", "YourControllerName", new {platilloId=Model.PlatilloId}); }
Change your controller method:
public ActionResult _Ingredientes(int platilloId )
{
return PartialView( "_IngredientView", db.Platillos.where(p=>p.PlatilloId==platilloId ).Ingredients.ToList();
}
Good luck
How I solved it: I just created a new Method, that encompassed both the Method i was originally using, and the method i wanted to use for my PartialView The rest was just using Lists to keep track of my data =D

Adding jQuery to forms with the same model in MVC3

I am trying to have two submission forms with similar functionality on the same view, where each form is strongly typed to the same model. I then am trying to add a datepicker to the same input on both forms, but I am unsure of how to do this. Here is my code:
#using (#Ajax.BeginForm(...
new { id = "editScheduleForm" }))
{
<div class="editor-label">
#Html.LabelFor(model => model.StartTime)
</div>
<div class="editor-field">
<input
#Html.EditorFor(model => model.StartTime)
#Html.ValidationMessageFor(model => model.StartTime)
</div>
}
...
#using (#Ajax.BeginForm(...
new { id = "addScheduleForm" }))
{
<div class="editor-label">
#Html.LabelFor(model => model.StartTime)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.StartTime)
#Html.ValidationMessageFor(model => model.StartTime)
</div>
}
Both of these forms are in their own strongly-typed partial views. I naturally tried simply adding the datepicker in jQuery to both partial views, like so:
$(function () {
$("#StartTime").datepicker();
});
But it unsurprisingly only worked for one of the inputs. I have been trying to use the HTML id that I added to both Ajax form declarations (e.g. editScheduleForm and addScheduleForm), but am unsure of how to do this. Any suggestions?
Solution:
As scottm suggested, I looked through documentation for using a custom editor template. I read this, detailing functionality I didn't know existed:
http://msdn.microsoft.com/en-us/library/ee407399.aspx
Here, you can specify a template, and then add a parameter for the htmlFieldName, which is specifically designed to circumvent the problem I was happening.
You can add a class to the inputs in your editor template. Then you can then use the class as the jQuery selector.
Add a file called DateTime.cshtml under ~/Views/Shared/EditorTemplates, and add the following:
#model DateTime
#Html.TextBox("", (Model.HasValue ? Model.Value.ToShortDateString() : string.Empty), new { #class = "date" })
Then add this jQuery to the page.
$(function () {
$(".date").datepicker();
});
The ID must be unique in a document.
Never rely on multiple ids on a page working correctly. Matter of fact, despite what most examples in blogs do, you should hardly ever use ids as jquery selectors.
Like #scottm said. You should use classes to tag items which you want to be widget-ized.
Here's a simplistic bit of code so you can create jq ui widgets declaratively:
$(function() {
$('[data-usewidget]').each(function() {
var $this = $(this), widget = $this.data('usewidget');
$.fn[widget] && $this[widget]();
});
});
Then in your html
<input name=startTime data-usewidget=datepicker />

How to change dynamically the value of a label in MVC 3?

I'm developing a project in MVC 3 (CRUD)... I want to create a reservation for a tennis court...
Page:
So, when I type a "Start time" ("heure de début" in French) I want to increase the "FinishTime" in red ("heure de fin" in French) dynamically... If it's a simple match increase by 1:00 and if not by 2:00...
I'm beginner in MvC3 so I have no idea how to do that... Of course, I'm not request that you make my work but the right method to do that and if it's possible an example...
View:
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Reservation</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Date)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Date)
#Html.ValidationMessageFor(model => model.Date)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.StartTime)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.StartTime)
#Html.ValidationMessageFor(model => model.StartTime)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Simple)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Simple)
#Html.ValidationMessageFor(model => model.Simple)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FinishTime)
</div>
<div class="editor-fieldFinishTime">
#Html.DisplayFor(model => model.FinishTime)
#Html.ValidationMessageFor(model => model.FinishTime)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Customer.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Customer.Name)
#Html.ValidationMessageFor(model => model.Customer.Name)
</div>
<div class="editor-label">
#Html.Label("Terrain N°")
</div>
<div class="editor-field">
#Html.DropDownListFor(c=>c.TennisCourtID,ViewBag.TennisCourtID as SelectList)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
I've forget to precise that all clubs can have different schedule... For example:
Club 1:
Simple: 1:00
Double: 2:00
Club2:
Simple: 1:30
Double: 2:30
So in my database's table TennisClub I have an attribute SimpleGameTime and DoubleGameTime... Sorry :(
Bind to the change event of the Input for Start time (check its ID in rendered HTML):
$("input#TheId").bind("onchange", onStartTimeChanged);
Define a function to parse a time, see this post here on SO.
In the onStartTimeChanged function get the check box state (update with correct jQuery selector for the control):
var checked = $('input[type=checkbox]').is(':checked');
Then simply add the parsed date with the proper offset and write that back to the End Time control using toLocaleTimeString().
Note: I assumed you'll use JavaScript to perform calculations on client-side. If you prefer to do everything on server-side you have to add an AJAX-enabled method in your controller with the start time and the flag as parameters. In your onStartTimeChanged function you have to call it and asynchronously update the end time when the function return. If there's a lot of logic (or it's not trivial) I prefer the server-side solution with AJAX.
For example (I didn't check the code so use it cum grano salis) to call a server-side method with POST (you have to pass parameters, as alternative you may use getJson with GET only but you have to work with routing):
function ComputeEndTime(matchStartTime, isSimpleMatch) {
var url = '<%= Url.Action("ControllerName", "ComputeEndTime") %>';
$.post(url, { startTime: matchStartTime, isSimple: isSimpleMatch },
function(data) {
return data.endTime;
}
);
}
And your server side function:
[AcceptPost]
public ActionResult ComputeEndTime(string startTime, bool isSimple)
{
// Perform your calculations then convert to string
string calculatedEndTime = "";
return Json(new { endTime = calculatedEndTime });
}

MVC3 Passing Model to Controller - Receiving Null values

I just started working with MVC3 a few weeks ago and being young in the programming ladder I'm still learning quite a bit. I've recently been working with Models, using TextBoxFor and other helpers to populate properties for my "Character" Model.
Essentially what I'm trying to do is define a model and then pass it to my controller, however any property that I have defined as a static value in my Model is being passed as a null value on runtime.
Below are some snippets of the parts needed to understand whats going on..
Character.cs - Model
// Instances of manipulated objects.
otReal db = new otReal();
public player newPlayer = new player();
public byte[] conditions
{
get
{
return newPlayer.conditions;
}
set
{
byte[] array1 = null;
array1 = new byte[16 * 12 * 3];
newPlayer.conditions = array1;
}
}
CharacterController.cs
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Submit(Character c)
{
// Add a new character to the database via LINQ to Entities.
otReal.AddToplayers(c.newPlayer);
otReal.players.AddObject(c.newPlayer);
otReal.SaveChanges();
return View();
}
The only helpers I have in my View are the ones that the user actually needs to interact with. If I go into my controller and set the values there they will get set to the correct value and it will insert. Any help would be greatly appreciated!
Index.cshtml - View
#using (Ajax.BeginForm("Submit", new AjaxOptions { OnComplete = "done" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>New Character Information</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Name, "Character Name")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.TownList)
</div>
<div class="editor-field">
#* #Html.DropDownList("TownList", ViewData["TownList"] as SelectList)*#
#Html.DropDownListFor(model => model.TownList, ViewData["TownList"] as SelectList)
#Html.ValidationMessageFor(model => model.TownList)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Sex)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Sex, ViewData["sex"] as SelectList)
#Html.ValidationMessageFor(model => model.Sex)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Vocation)
</div>
<div class="editor-field">
#Html.DropDownList("VocList", ViewData["VocList"] as SelectList)
#Html.ValidationMessageFor(model => model.Vocation)
</div>
<p>
<input id="button" type="submit" value="Create" />
</p>
<div style="font-family: Tahoma; font-size: large" id="completeDiv" style="display: none;">
</div>
<span></span>
</fieldset>
}
Basically what I'm trying to do here is create my model that has a bunch of base values that every 'Character' will have in the database table. This way when a player creates his/her character he/she will be able to enter a Character Name, Sex, Class(Vocation), Starting Town and all the other values will be populated behind the scenes and passed to the controller for creation.
Assuming you're trying to set values on 'newPlayer', then you can replace this
public player newPlayer = new player();
with this
public player newPlayer { get; set; }
The default model binder will create everything from the form on post-back--there's no need to instantiate it in the model.
Created a constructor for my model and inside the constructor I set the default values via the newly instantiated player model. Temp fix until I read into ataddeini's solution. Thanks everyone!

Categories