Passing a model through a Partial View MVC3 - c#

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

Related

MVC 4: Some fields return as null when editing entity

I have an Edit view which displays some of my fields as follows:
<table>
<tr>
<td style="width:40%; vertical-align:top">
<div class="editor-label">
#Html.LabelFor(model => model.CREATED_DATE)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.CREATED_DATE)
#Html.ValidationMessageFor(model => model.CREATED_DATE)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LAST_MODIFIED_DATE)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.LAST_MODIFIED_DATE)
#Html.ValidationMessageFor(model => model.LAST_MODIFIED_DATE)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.STATUS)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.STATUS, Model.Statuses)
#Html.ValidationMessageFor(model => model.STATUS)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.SEVERITY)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.SEVERITY, Model.Severities)
#Html.ValidationMessageFor(model => model.SEVERITY)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PRIORITY)
</div>
<div id="priorityDiv" class="editor-field">
#Html.EditorFor(model => model.PRIORITY)
#Html.ValidationMessageFor(model => model.PRIORITY)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DESCRIPTION)
</div>
<div id="descriptionDiv" class="editor-field">
#Html.EditorFor(model => model.DESCRIPTION)
#Html.ValidationMessageFor(model => model.DESCRIPTION)
</div>
</td>
</tr>
</table>
In essence I want users to be able to edit any field except for the two at the top, CREATED_DATE and LAST_MODIFIED_DATE. However, when I hit the submit button the two date fields come back as null. My controller code is below.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Alert alert)
{
if (ModelState.IsValid)
{
alert.LAST_MODIFIED_DATE = DateTime.Now;
db.Entry(alert).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(alert);
}
Is there a way to prevent the user from editing a field in a View without the content of filed being returned to the controller as null?
Add them to your view in hidden fields inside the form:
<div class="editor-field">
#Html.DisplayFor(model => model.CREATED_DATE)
#Html.HiddenFor(model => model.CREATED_DATE)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.LAST_MODIFIED_DATE)
#Html.HiddenFor(model => model.LAST_MODIFIED_DATE)
</div>
This will make them post back to your Edit method without the user being able to edit them. You can also remove the ValidationMessages for this fields as they cannot be edited and therefore won't need to display validation messages.
EDIT:
As #JLRishe pointed out this would give the users the power to edit the values using their browsers debug tools.
Another solution could be to create a view specific model, and only map the values you want adjusted to your database object. More info about that here: Real example of TryUpdateModel, ASP .NET MVC 3

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 });
}

Fail to submit a list of object to the model binding using ICollection

i have added extra three input fields to my view to enable the system admin to submit four objects at the same time instead of one object at a time; the view looks as the following:-
#model Elearning.Models.Answer
#{
ViewBag.Title = "Create";
}
<div id = "partialWrapper">
#using (Ajax.BeginForm("Create", "Answer", new AjaxOptions
{
HttpMethod = "Post",
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = "incrementanswer",
OnSuccess = "removePartial",
LoadingElementId = "progress2"
}))
{
<div id = "returnedquestion">
#Html.ValidationSummary(true)
<fieldset>
<legend>Answer here</legend>
<ol>
<li> <div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.TextBox("answer[0].Description")
#Html.ValidationMessageFor(model => model.Description)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.IsRight)
</div>
<div class="editor-field">
#Html.DropDownList("IsRight", String.Empty)
#Html.ValidationMessageFor(model => model.IsRight)
</div>
</li>
<li> <div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.TextBox("answer[1].Description")
#Html.ValidationMessageFor(model => model.Description)
</div> <div class="editor-label">
#Html.LabelFor(model => model.IsRight)
</div>
<div class="editor-field">
#Html.DropDownList("IsRight", String.Empty)
#Html.ValidationMessageFor(model => model.IsRight)
</div> </li>
<li> <div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.TextBox("answer[2].Description")
#Html.ValidationMessageFor(model => model.Description)
</div> <div class="editor-label">
#Html.LabelFor(model => model.IsRight)
</div>
<div class="editor-field">
#Html.DropDownList("IsRight", String.Empty)
#Html.ValidationMessageFor(model => model.IsRight)
</div> </li>
<li> <div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.TextBox("answer[3].Description")
#Html.ValidationMessageFor(model => model.Description)
</div> <div class="editor-label">
#Html.LabelFor(model => model.IsRight)
</div>
<div class="editor-field">
#Html.DropDownList("IsRight", String.Empty)
#Html.ValidationMessageFor(model => model.IsRight)
</div> </li>
<ol>
</fieldset>
<input type= "hidden" name = "questionid" value = #ViewBag.questionid>
<input type= "hidden" name = "assessmentid" value = #ViewBag.assessmentid>
<input type="submit" value="Add answer" />
</div>
}
</div>
and the following Post Ation Method:-
[HttpPost]
public ActionResult Create(int questionid, ICollection<Answer> answer)
{
if (ModelState.IsValid)
{
foreach (var a in answer){
repository.AddAnswer(a);
repository.Save();
}
return PartialView("_details2",answer);
}
return View("_details2",answer);}
and last thing the _details2 partial view which contains the newly added objects:-
#model IEnumerable<Elearning.Models.Answer>
#{
ViewBag.Title = "Details";
}
#foreach (var m in Model)
{
<tr id = #m.AnswersID>
<td>
#Html.DisplayFor(modelItem => m.Description)
</td>
<td>
#*#Html.DisplayFor(modelItem => Model.Answer_Description.description)*#
#ViewBag.Answerdesription
</td>
<td>
#Ajax.ActionLink("Delete", "Delete", "Answer",
new { id = m.AnswersID },
new AjaxOptions
{
Confirm = "Are You sure You want to delete this Answer ?",
HttpMethod = "Post",
UpdateTargetId = #m.AnswersID.ToString(),
OnSuccess = "removePartial2"
})
</td>
</tr>
}
but the above is not working nethier the objects will be added nor the partial view will be returned , so how i can solve this issue???
BR
You bind your view to a single Elearning.Models.Answer object, how are you expecting to get a collection of Answers as a parameter in your Action? The default model binder will try to bind your view fields to the parameter in the Action but it won't be able to as it's a collection.
What you could try to do is to bind your View to a List<Elearning.Models.Answer> and feed it 4 empty Answer objects, then you can create a strongly typed Partial view that expects one Elearning.Models.Answer, add the Partial in a foreach and, when posting the form, expect that the default model binder does it work and fill your action method with a brand new List of Answer objects.
As an alternative, you can create a View Model object that contains the fields in your View, including those 4 description fields. You add them as Html.TextboxFor to bind each of them to a different property in the View Model. Then you can collect them in your action, provided you change it to public ActionResult Create(int questionid, ViewModelAnswer answer)
Does it make sense?
Your model should contain a list and code like this:
#for (int i=0; i < Model.FavouriteMovies.Count; i++) {
#Html.LabelFor(model => model.YourList[i].Field)
#Html.EditorFor(model => model.YourList[i].Field)
#Html.ValidationMessageFor(model => model.YourList[i].Field)
}
which will print something like:
<label for="YourList_0__Field">Field Name</label>
The Field Name field is required.
And receive the model back in your controller:
public ActionResult MyAction(MyModel model)
{
// First element?
model.YourList[0].
}

How to add data to both: Category id and Name Category from one Html.LabelFor?

In the view Create i want to add a new product. I need from the drop down list to select the category name. The problem is, that i have in the table Products add only the category id. And how me add and name too of category?
Structure my DB:
Table Brand: idbrand, name.
Table Make: idbrand, namebrand, idmake, name, price, urlmake.
I do the following:
// GET: /ShopManager/Create
public ActionResult Create()
{
ViewBag.BrandID = new SelectList(db.Brand, "BrandID", "Name");
return View();
}
//
// POST: /ShopManager/Create
[HttpPost]
public ActionResult Create(Make make)
{
if (ModelState.IsValid)
{
db.Make.AddObject(make);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.BrandID = new SelectList(db.Brand, "BrandID", "Name", make.BrandID);
return View(make);
}
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Марка телефона</legend>
<div class="editor-label">
#Html.LabelFor(model => model.BrandID, "Бренд")
</div>
<div class="editor-field">
#Html.DropDownList("BrandID", String.Empty)
#Html.ValidationMessageFor(model => model.BrandID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.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.Price, "Цена")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Price)
#Html.ValidationMessageFor(model => model.Price)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.UrlMake, "Изображение")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UrlMake)
#Html.ValidationMessageFor(model => model.UrlMake)
</div>
<p>
<input type="submit" value="Создать" />
</p>
</fieldset>
<div>
#Html.ActionLink("Back to List", "Index")
</div>
How me add in Table Make BrandID and Name of Brand(name of Category)?
Since you have a Brand table it's not necessary to store brand's name in the Make also, you could get that with a simple join. Anyway if you really want to do that in the Create you can set it as the following code
make.NameBrand = db.Brand.Where(b => b.idbrand == make.idbrand).SingleOrDefault().namebrand;

Getting View data

Hy Guys!
I don't know how to get this data on my controller. could somebody help me?
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Pedido</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Assunto)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Assunto)
#Html.ValidationMessageFor(model => model.Assunto)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Data)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Data)
#Html.ValidationMessageFor(model => model.Data)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Tks.
You should make an overload of the action method that takes the model as a parameter.
MVC will do the rest.

Categories