I have created a ViewModel with two things, a Contact and a list of Phones for that Contact.
My goal is to add data for a new Contact, and add a few Phones, and then save by a Controller action.
I've edited the scaffolded Create.cshtml for my Contact, added a grid for the phones. Added a javascript for creating the phones. So far so good.
The problem is when I click the Create button, and I get back to the Controller, I get no Phones. How do I (in the View) add the phone-rows to my IEnumerable?
EDIT:
Took out code in view that was not correct in this context.
My ViewModel:
public class ContactViewModel
{
public Contact Contact {get; set;}
public IEnumerable<Phone> Phones { get; set; }
}
My view:
#model PilotKibsNet.Controllers.ContactViewModel
<script type="text/javascript" src="../../Scripts/jquery-1.5.1.js"></script>
#{
ViewBag.Title = "Create";
}
<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>
<script type="text/javascript">
function Add() {
$("#tbl > tbody:last").append("<tr><td>" + $("#Number").val() + "</td><td>" + $("#Kind").val() + "</td><td></td></tr>");
$("#Number").val("");
$("#Kind").val("");
}
</script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Contact</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Contact.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Contact.Name)
#Html.ValidationMessageFor(model => model.Contact.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Contact.Address)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Contact.Address)
#Html.ValidationMessageFor(model => model.Contact.Address)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Contact.City)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Contact.City)
#Html.ValidationMessageFor(model => model.Contact.City)
</div>
<legend>Phone numbers</legend>
<label>Number :</label>
#Html.TextBox("Number")
<label>Kind :</label>
#Html.TextBox("Kind")
<input type="button" value="Add" onclick="Add()" />
<table id="tbl">
<tr>
<th>
Phone
</th>
<th>
Kind
</th>
<th></th>
</tr>
<tbody>
</tbody>
</table>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
And then, in by Controller action, the Contact has the data, but the Phone is an empty list.
[HttpPost]
public ActionResult Create(ContactViewModel contactViewModel)
{
if (ModelState.IsValid)
{
contactViewModel.Contact.id = Guid.NewGuid();
db.Contacts.AddObject(contactViewModel.Contact);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(contactViewModel.Contact);
}
How do I get the Phones back to the server?!?
You have only display templates for those Phones collection. No value at all will be sent to the server. You could use hidden fields if the user is not supposed to edit the values or textboxes if he is.
Also I would replace this foreach loop in your view by an editor template:
if (Model != null)
{
#Html.EditorFor(x => x.Phones)
}
and then I will define an editor template which would be rendered for each element of the Phones collection (~/Views/Shared/EditorTemplates/Phone.cshtml):
#model Phone
<tr>
<td>
#Html.DisplayFor(x => x.Number)
#Html.HiddenFor(x => x.Number)
</td>
<td>
#Html.DisplayFor(x => x.Type)
#Html.HiddenFor(x => x.Type)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = Model.id }) |
#Html.ActionLink("Details", "Details", new { id = Model.id }) |
#Html.ActionLink("Delete", "Delete", new { id = Model.id })
</td>
</tr>
I have used hidden fields here to persist the values of the model so that when you post the form to the server they would be sent.
Another and IMHO better approach if the user is not supposed to edit those values in the table is to simply refetch them in your POST action from your database.
Related
I need to make a custom data grid view with multi column filtering and pagination. so i made a view model winch will encapsulate three class
IEnumerable from the data.
Filter class with some properties
Pager to holder page size, current page, total pages etc ..
Filtering working fine but pagination not :(. as i loose the view model when pressing pagination link "It seems that i need to also submit the search form"
Any one can show how i can submit the form when pressing a link.
here is my view
#model TestFilteringAndPagination.ViewModels.CarViewModel
#{
ViewBag.Title = "Home Page";
}
#*Search form*#
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "frm" }))
{
#Html.HiddenFor(m => Model.Pager.CurrentPage)
#Html.HiddenFor(m => Model.Pager.PageSize)
#Html.HiddenFor(m => Model.Pager.EndPage)
#Html.HiddenFor(m => m.Pager.StartPage)
<div class="form-inline">
<div class="form-group">
<label>Car No</label>
#Html.EditorFor(x => x.Filter.CarNumber, new { #class = "form-control" })
</div>
<div class="form-group">
<label>Line name</label>
#Html.EditorFor(x => x.Filter.LineName, new { #class = "form-control" })
</div>
<button type="submit" class="btn btn-default">Search</button>
</div>
<ul class="pagination">
#for (var page = Model.Pager.StartPage; page <= Model.Pager.EndPage; page++)
{
<li class="#(page == Model.Pager.CurrentPage ? "active" : "")">
#page
</li>
}
</ul>
}
#*Data grid*#
<table class="table">
<thead>
<tr>
<th>
Car number
</th>
<th>
Car Line
</th>
</tr>
</thead>
<tbody>
#foreach (var car in Model.Cars)
{
<tr>
<td>
#Html.DisplayFor(x => car.CarNumber)
</td>
<td>
#Html.DisplayFor(x => car.LineName)
</td>
</tr>
}
</tbody>
</table>
You can install the PagedList.MVC NuGet Package, see this post for more info about how to create exactly what you want.
Sorting, Filtering, and Paging with the Entity Framework in an ASP.NET MVC Application
I have created create function in my controller which display all genres in checkoxes like this:
Controller:
public ActionResult Create()
{
var db = new MainDatabaseEntities();
var viewModel = new ANIME
{
GENRES = db.GENRES.Select(c => new { ID_GE = c.ID_GE, GENRE = c.GENRE, isSelected = false }).ToList().Select(g => new GENRES
{
ID_GE = g.ID_GE,
GENRE = g.GENRE,
isSelected = false
}).ToList()
};
return View(viewModel);
}
View:
#model AnimeWeb.Models.ANIME
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<table>
<tr>
<td class="lefttablecontent" id="top">
<div class="editor-label">
#Html.HiddenFor(model => model.ID_AN)
</div>
<div class="editor-label">
Original title
</div>
<div class="editor-field">
#Html.EditorFor(model => model.TITLE_OR)
#Html.ValidationMessageFor(model => model.TITLE_OR)
</div>
<div class="editor-label">
English title
</div>
<div class="editor-field">
#Html.EditorFor(model => model.TITLE_EN)
#Html.ValidationMessageFor(model => model.TITLE_EN)
</div>
<div class="editor-label">
Genres
</div>
<div class="editor-list">
#Html.EditorFor(model => model.GENRES)
#Html.ValidationMessageFor(model => model.GENRES)
</div>
</td>
<td class="righttablecontent" id="top">
<p>
<input type="submit" value="Create" />
</p>
</td>
</tr>
</table>
}
}
EditorTemplate for Genres:
#model AnimeWeb.Models.GENRES
#Html.HiddenFor(model => model.ID_GE)
#Html.HiddenFor(model => model.GENRE)
<table>
<tr>
<td class=" right">
#Html.EditorFor(model => model.isSelected)
</td>
<td>
#Html.LabelFor(model => model.isSelected, Model.GENRE)
</td>
</tr>
</table>
Now I would like to display the same template with all genres and use it for filtering in index, but I'm not sure how to do this.
Controller:
public ActionResult Index(string sortOrder, string currentFilter, int? page)
{
using (var db = new MainDatabaseEntities())
{
ViewBag.CurrentSort = sortOrder;
if (searchString != null)
{
page = 1;
}
else
{
searchString = currentFilter;
}
ViewBag.CurrentFilter = searchString;
var anime = from s in db.ANIME.Include("GENRES")
select s;
int pageSize = 10;
int pageNumber = (page ?? 1);
return View(anime.ToPagedList(pageNumber, pageSize));
}
}
View:
#model PagedList.IPagedList<AnimeWeb.Models.ANIME>
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Index";
}
<p>
#if (Roles.IsUserInRole("Administrator"))
{
#Html.ActionLink("Create New", "Create")
}
</p>
#foreach (var item in Model) //
{ //
#Html.EditorFor(modelItem => item.GENRES); // I'm not sure about this line
} //
<table>
<tr>
<th>
Anime
</th>
<th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.ActionLink(item.TITLE_OR, "Details", new { id = item.ID_AN })
</td>
</tr>
}
</table>
<br />
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("Index",
new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
When I try to display it with #Html.EditorFor(modelItem => item.GENRES) it displays only genres that are selected within each anime but I need all genres to filter with them. I'm not even sure is this a good way to make it. Any suggestions?
I have a model with a DateCreated value that is not scaffolded. Coming to GET Edit controller action I see that the model has a correct value that is passed on to the Edit view. Coming back from the view, POST method, the value for DateCreated is DateTime default. It's lost.
Does anyone know why? Controller and View are scaffolded.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Product product)
{
try
{
if (ModelState.IsValid)
{
product.DateEdited = DateTime.Now;
db.Entry(product).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DataException dex)
{
Console.Write(dex.Message);
ModelState.AddModelError("", reg6.Resources.UnableToSaveChanges);
}
return View(product);
}
#model reg6.Models.Product
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Product</legend>
<table>
<tr>
<td>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
</td>
<td>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
<div>
#Html.ValidationMessageFor(model => model.Name)
</div>
</div>
</td>
<tr>
<tr>
<td>
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
</td>
<td>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
<div>
#Html.ValidationMessageFor(model => model.Description)
</div>
</div>
</td>
<tr>
<tr>
<td>
<div class="editor-label">
#Html.LabelFor(model => model.BasePrice)
</div>
</td>
<td>
<div class="editor-field">
#Html.EditorFor(model => model.BasePrice)
<div>
#Html.ValidationMessageFor(model => model.BasePrice)
</div>
</div>
</td>
<tr>
<tr>
<td>
<div>
#Html.ActionLink("Back to List", "Index")
</div>
</td>
<td align="right">
<input type="submit" value="Create" id='CreateButton' />
<td>
</tr>
</table>
</fieldset>
}
In your view place a hidden element for the DateCreated
#Html.HiddenFor(m=>m.DateCreated)
All the hidden elements will be posted to the server.
Hi how are you? I'm trying to validate a form in ASP NET MVC.
I have a partial view "Address" that I reuse for some entities, like Company, Person, etc.
My problem is that when I submit the form, only the controls of the father view gets validated, the ones in the partial view don't.
Here's some code I hope u can geive me hand
PERSON VIEW
#model Entities.Person
#using (Html.BeginForm("Create", "Person", FormMethod.Post))
{
<table>
<tr>
<td>
#Html.LabelFor(model => model.FirstName)
<div class="control">
#Html.TextBoxFor(model => model.FirstName, new { #maxlength = 7, #class = "numeric"})
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="spacer-short"></div>
</td>
<td>
#Html.LabelFor(model => model.LastName)
<div class="control">
#Html.TextBoxFor(model => model.LastName, new { #maxlength = 7, #class = "numeric"})
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="spacer-short"></div>
</td>
</tr>
</table>
#{ Html.RenderAction("Index", "Address", new {id = Model.AddressId});} //Renders the Address form part
<div class="spacer"></div>
<button type="submit" data-button="true" data-button-icon="ui-icon-disk" class="">Create</button>
<button type="button" data-button="true" data-button-icon="ui-icon-circle-close" class="button-cancel">Cancel</button>
}
ADDRESS VIEW
#model Entities.Address
<table>
<tr>
<td>
#Html.LabelFor(model => model.Street)
<div class="control">
#Html.TextBox("Address.Street", Model.Street)
#Html.ValidationMessage("Address.Street")
</div>
<div class="spacer-short"></div>
</td>
<td>
#Html.LabelFor(model => model.Number)
<div class="control">
#Html.TextBox("Address.Number", Model.Number)
#Html.ValidationMessage("Address.Number")
</div>
<div class="spacer-short"></div>
</td>
</tr>
</table>
Then I have some validation metadata ([Required]) for person and address fields
A common mistake using #Html.Partial(...) and expecting validation errors to show up is not passing ViewData to that partial.:
#Html.Partial([ViewName], [EmailAddressObject], ViewData)
Try this:
#Html.EditorFor(Model.Street)
#Html.ValidationMessageFor(Model.Street)
instead of this:
#Html.TextBox("Address.Street", Model.Street)
#Html.ValidationMessage("Address.Street")
Try using Html.Partial(...) instead of Html.RenderAction(...) to render the partial view. This may be suppressing the validations.
Model
İmportant: Manage Nuget Packages
=>> JQuery.Validation
=>> Microsoft.JQueryUnobtrusive.Validation
install.
1) First step
using System.ComponentModel.DataAnnotations;
2)
public int Id { get; set; }
[Required(ErrorMessage = "* Kategori adı boş geçilemez.")]
[DisplayName("Kategori Adı")]
public string CategoryName { get; set; }
[Required(ErrorMessage = "* Kategori açıklaması boş geçilemez.")]
[DisplayName("Kategori Açıklaması")]
public string Description { get; set; }
3)
if (model != null && ModelState.IsValid)
{
var categoryCreate = new Categories
{
//code
};
_CategoriesService.Create(categoryCreate);
}
4)
Add ViewModel
#model Models.CategoryViewModel
After
#Html.TextBoxFor(model => model.CategoryName, new { #class = "form-control input-sm", id = "categoryTitle", #placeholder = "Kategori adını giriniz.", #type= "text", #required=true })
#Html.ValidationMessageFor(model => model.CategoryName, "", new { #class = "error-message" })
#Html.TextBoxFor(model => model.Description, new { #class = "form-control input-sm", id = "categoryArticle", #placeholder = "Kategori açıklamasını giriniz.", #type = "text", #required = true })
#Html.ValidationMessageFor(model => model.Description, "", new { #class = "error-message" })
In my case, I was missing
<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>
Once I put that in my _layout.cshtml file, it started working even with partial views.
2 Points
3 Posts
Data from view to different controller
1 minute ago|LINK
Hello friends
I'm from Colombia, sorry for the writing
I have a problem I do not know how to connect two controllers from one view, I'm using EF Data Base First, this automatic genre classes to my model, one of these classes is called "UNIVERSITY" which is a table of the database where are all the universities, and another class is "CAMPUS_UNIVERSITY" where are all the campus of a university, a university can have multiple campus
I have 2 controllers and their associated views
The first controller is "University" (I think i not necessary show) and your view "Index" (list all Universidadades). That is this:
#model IEnumerable<RolesMVC3.Models.UNIVERSITY>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
Nombre
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.ActionLink("Add Campus", "Create", "CampusUniversity" new { id=item.IdUniversity }) |
#Html.ActionLink("Edit", "Edit", new { id=item.IdUniversity }) |
#Html.ActionLink("Delete", "Delete", new { id=item.IdUniversity })
</td>
</tr>
}
</table>
The link "Add Campus" routed to controller "CampusUniversity" to the action "Create". That is this:
public ActionResult Create()
{
ViewBag.IdCityCampus = new SelectList(db.CITY_CAMPUS, "IdCityCampus", "Name");
ViewBag.IdUniversity = new SelectList(db.UNIVERSITY, "IdUniversity", "Name");
return View();
}
//
//
[HttpPost]
public ActionResult Create(CAMPUS_UNIVERSITY campus_university)
{
if (ModelState.IsValid)
{
db.CAMPUS_UNIVERSITY.AddObject(campus_university);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.IdCityCampus = new SelectList(db.CIUDAD_SEDE, "IdCityCampus", "Nombre", campus_university.IdCityCampus);
ViewBag.IdUniversity = new SelectList(db.UNIVERSIDAD, "IdUniversity", "Nombre", campus_university.IdUniversity);
return View(campus_university);
}
And the associated view (View "Create" Controller " CampusUniversity ") is:
#model RolesMVC3.Models.CAMPUS_UNIVERSITY
#{
ViewBag.Title = "Create";
}
<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>SEDE_UNIVERSIDAD</legend>
<div class="editor-label">
#Html.LabelFor(model => model.IdUniversity, "UNIVERSIDAD")
</div>
<div class="editor-field">
#Html.DropDownList("IdUniversity", String.Empty)
#Html.ValidationMessageFor(model => model.IdUniversity)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.IdCityCampus, "CITY_CAMPUS")
</div>
<div class="editor-field">
#Html.DropDownList("IdCityCampus", String.Empty)
#Html.ValidationMessageFor(model => model.IdCityCampus)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.AddressCampus)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.AddressCampuse)
#Html.ValidationMessageFor(model => model.AddressCampus)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PhoneCampus)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PhoneCampus)
#Html.ValidationMessageFor(model => model.PhoneCampus)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.MailCampus)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.MailCampus)
#Html.ValidationMessageFor(model => model.MailCampus)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
I want to do that by clicking "Add Campus" appears the name of the university comes fromthe table or class "UNIVERSITY" in the view Create (controller "SedeUniversidad") and that can save the campus of the university and not as I have now, because I have to choose the university of a DropDownList, how I can do?
Thank you, blessings!
I can't understand some of your English. It sounds like you want to send data from your Create view to your University controller. You can make the POST url of your form go wherever you want by putting the following values in your HTML.BeginForm statement in your Create view.
#using (Html.BeginForm("ActionName", "ControllerName"))