i have problem creating view with multiple forms with in same view where i have get action for data view and post action for data collection.
Here is my main view:
#model Models.BuildingNewBuildingViewModel
#{
ViewBag.Title = "Index";
}
#if (TempData["Added"] != null)
{
<div class="alert alert-success alert-dismissible fade in" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
#TempData["Added"]
</div>
}
#if (TempData["AddError"] != null)
{
<div class="alert alert-danger alert-dismissible fade in" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
#TempData["AddError"]
</div>
}
<h1>Svěřené budovy pro: #ViewBag.Name</h1>
<table class="table-bordered table-responsive table table-condensed">
<thead>
<tr>
<th>Id budovy</th>
<th>Podlaží</th>
<th>Použití</th>
<th>Výměra</th>
<th>Datum</th>
<th>Administrace</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.NewBuildingViewModels.Count; i++)
{
using (Html.BeginForm("Index", "Home", FormMethod.Post, new { #class = "form-horizontal", id = "Form" }))
{
Html.RenderPartial("IndexPartial", Model.NewBuildingViewModels[i]);
}
}
</tbody>
</table>
Here is form:
#model Models.NewBuildingViewModel
#Html.HiddenFor(x => x.Building, Model.Building)
<tr>
<td>#Model.Building</td>
<td>
#if (Model.Floor > 0)
{
#Model.Floor
#Html.HiddenFor(x => x.Floor)
}
else
{
#Html.TextBoxFor(x => x.Floor, new {#Value = ""})
#Html.ValidationMessageFor(x => x.Floor)
}
</td>
<td>
#if (Model.Usage != null)
{
#Model.Usage
#Html.HiddenFor(x => x.Usage)
}
else
{
#Html.TextBoxFor(x => x.Usage)
#Html.ValidationMessageFor(x => x.Usage)
}
</td>
<td>
#if (Model.Size > 0)
{
#Model.Size
#Html.HiddenFor(x => x.Size)
}
else
{
#Html.TextBoxFor(x => x.Size, new {#Value = ""})
#Html.ValidationMessageFor(x => x.Size)
}
</td>
<td>
#if (Model.Date != DateTime.MinValue)
{
#Model.Date.Date
#Html.HiddenFor(x => x.Date)
}
else
{
#Html.TextBoxFor(x => x.Date)
#Html.ValidationMessageFor(x => x.Date)
}
</td>
<td>
#if (!Model.NewBuildingDataInDatabase)
{
<button type="submit">Odeslat</button>
}
else
{
if (Model.MarksInDatabase)
{
<i class="fa fa-check checkIcon" aria-hidden="true"></i>
}
else
{
Zadat Hodnocení
}
}
</td>
</tr>
}
And my problem is when i send non valid data to controller. Validation message shows for all forms. I want to see all forms but validation messages only for form which sended data.
Here is my action:
[HttpPost]
public ActionResult Index(NewBuildingViewModel buildingNewBuildingViewModel)
{
BuildingForIcoCommand buildingForIcoCommand = new BuildingForIcoCommand();
var buildingsForIco = buildingForIcoCommand.GetBuildingListForIco(AppContext);
if (ModelState.IsValid)
{
ViewBag.Name = User.Identity.Name;
ViewModelBuilder viewModelBuilder = new ViewModelBuilder();
DaoBase<NewBuilding, int> daoBase = new DaoBase<NewBuilding, int>(AppContext.NhSession);
daoBase.Save(viewModelBuilder.CreateNewBuilding(buildingNewBuildingViewModel));
return View(buildingForIcoCommand.GetBuildingListForIco(AppContext));
}
return View("Index",buildingsForIco);
}
All of your form fields will have the name and id attributes because you are rendering them in a partial. This is why they are all flagged as invalid.
Any good solution will probably involve ajax.
One approach to revolving this would be to use a single edit form. Each rendered item would have an edit button, clicking this button would populate the form with the item's data via javascript. This could be a modal or similar. This approach works well with jQuery / unobtrusive validation.
Another approach would be to return a custom response from your controller eg status 400 and the invalid fields derived from the model state. You can then show a suitable error message in the right field.
Related
On my Main View I have 4 partial views.. two are tables.. the others are create forms.
Partial View Table 1
#model IEnumerable<ProjectName.Models.code_AutoMake>
<h3>Auto Make List</h3>
<table id="Auto-Make-Table" class="table table-bordered table-striped">
<thead>
<tr>
<th class="col-md-5">
#Html.DisplayNameFor(model => model.AutoMake)
</th>
<th class="col-md-5">
#Html.DisplayNameFor(model => model.Active)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.AutoMake)
</td>
<td>
#Html.DisplayFor(modelItem => item.Active)
</td>
#if (!item.Active)
{
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.MakeID }) |
Activate
</td>
}
else
{
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.MakeID }) |
Deactivate
</td>
}
</tr>
}
</tbody>
</table>
Partial View Table 2
#model IEnumerable<ProjectName.Models.code_Funding>
<h3>Funding List</h3>
<table class="table table table-bordered table-striped">
<tr>
<th>
#Html.DisplayNameFor(model => model.Funding)
</th>
<th>
#Html.DisplayNameFor(model => model.Active)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Funding)
</td>
<td>
#Html.DisplayFor(modelItem => item.Active)
</td>
<td>
#Html.ActionLink("Edit", "Edit", "code_Funding",new { id=item.FundID }, null) |
</td>
</tr>
}
</table>
Partial View 1 Create
#model ProjectName.Models.code_AutoMake
#using (Html.BeginForm("Create", "code_AutoMake", FormMethod.Post))
{
#Html.AntiForgeryToken()
<h3>Add Auto Make</h3>
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="row">
<div class="col-sm-12 col-md-3">
#Html.Label("Auto Make")
#Html.EditorFor(model => model.AutoMake, new {htmlAttributes = new {#class = "form-control"}})
</div>
<div class="col-sm-12 col-md-3">
#Html.Label("Active")
<div class="checkbox">
#Html.EditorFor(model => model.Active)
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 col-md-3">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
Partial View 2 Create
#model ProjectName.Models.code_Funding
#using (Html.BeginForm("Create", "code_Funding", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<h3>Add Funding</h3>
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="row">
<div class="col-sm-12 col-md-3">
#Html.Label("Funding")
#Html.EditorFor(model => model.Funding, new {htmlAttributes = new {#class = "form-control"}})
</div>
<div class="col-sm-12 col-md-3">
#Html.Label("Active")
<div class="checkbox">
#Html.EditorFor(model => model.Active)
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 col-md-3">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
Main View
<div id="AutoMake" class="tab-pane fade active in">
<div id="AutoMake-Index">#{Html.RenderAction("Index", "code_AutoMake");}</div>
<hr/>
#{Html.RenderAction("Create", "code_AutoMake");}
</div>
#*Funding*#
<div id="Funding" class="tab-pane fade">
#{Html.RenderAction("Index", "code_Funding");}
<hr/>
#{Html.RenderAction("Create", "code_Funding");}
</div>
Now here is the scenario.. When I want to create a new autoMake.. I fill out the form and hit submit.. this goes through fine.. until I get back to the Main View.. specifically this line:
#{Html.RenderAction("Create", "code_Funding");}
and I get a runtime error saying:
Child Actions are not allowed to perform redirect actions
I have debugged.. and for some reason.. the HttpPost Create action for code_Funding is being hit.. even when I'm not filling out the create form for code_funding.. How is that possible?
Here are my Create Methods for code_autoMake and code_funding:
code_Funding
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "FundID,Funding,Active")] code_Funding code_Funding)
{
try
{
if (ModelState.IsValid)
{
db.code_Funding.Add(code_Funding);
db.SaveChanges();
return RedirectToAction("EditDDL", "tblNewAutos");
}
}
catch (DbEntityValidationException ex)
{
foreach (var entityValidationErrors in ex.EntityValidationErrors)
{
foreach (var validationError in entityValidationErrors.ValidationErrors)
{
Response.Write("Property: " + validationError.PropertyName + " Error: " + validationError.ErrorMessage);
}
}
}
return RedirectToAction("EditDDL", "tblNewAutos");
}
code_autoMake
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "MakeID,AutoMake,Active")] code_AutoMake code_AutoMake)
{
if (ModelState.IsValid)
{
db.code_AutoMake.Add(code_AutoMake);
db.SaveChanges();
return PartialView("~/Views/PartialViews/_AutoMakeCreate.cshtml");
}
return RedirectToAction("EditDDL", "tblNewAutos");
}
Why when I try and create a new automake.. both HttpPost Create methods are hit?
Any help is appreciated.
Well, the problem is following. In your main view you have got this code:
...
#{Html.RenderAction("Create", "code_AutoMake");}
...
Which triggers the Create action which finishes with the following line of code if ModelState.IsValid == false:
return RedirectToAction("EditDDL", "tblNewAutos");
That is obviously a bad idea. Why? You are already in a process of rendering a parent view. Child actions might be a bit confusing at first because they are not real actions - no client/server communication. You are still on the server side. Therefore no redirect is allowed in the child action.
Solutions
First of all, I am not quite sure what you want to achieve so my solution recommendation might be a bit off, but let's see.
Option 1
You may want to use two different actions. One that is called on submit of the form and another one that is called from your main view. The latter one should not make a redirect - instead it should wisely choose which view to render based on the ModelState.IsValid if this is really what you need.
Option 2
There is a hack way which allows you to make redirect from a child action. Instead of making a redirect, only store information about required redirect for instance in HttpContext.Items collection. Then, implement an ActionFilter and in its OnResultExecuted event, check if the redirect request was set to the HttpContext.Items. If so, make a redirect. The ActionFilter should be applied on the parent action, not on the child action.
#{Html.RenderAction("Create", "code_Funding");}
in this RenderAction Method is call the GET request but, your controller you written only post method. and you write the
[ChildActionOnly]
public ActionResult Create(string parm)
{
reurn view()
}
and use [ChildActionOnly] this attribute is allowing restricted access via code in View.
Check and reply me..
I have an ASP.NET MVC app. This app has a view that shows a list of records. I want to let my users add a record to this list. To do that, I've created a dialog that the user can enter information into. At this time, this dialog is a partial. I'm willing to change the implementation. I just need a dialog for adding. At this time, my views look like this:
Index.cshtml
<table class="table">
<thead>
<tr>
<th></th>
<th>First Name</th>
<th>Last Name</th>
<th>Email address</th>
</tr>
</thead>
<tbody>
#foreach (var user in Model.Users)
{
<tr>
<td></td>
<td>#user.FirstName</td>
<td>#user.LastName</td>
<td>#user.Email</td>
</tr>
}
</tbody>
</table>
<br />
<button type="button" class="btn btn-default" onclick="addPerson()">Add Person</button>
#* Add Person dialog *#
<div id="addPersonModal" class="modal">
<div class="modal-dialog">
#{Html.RenderAction("Add", "Person");}
</div>
</div>
<script type="text/javascript">
function addPerson() {
$('#addPersonModal').modal('show');
}
</script>
Add.cshtml
#model MyApp.Models.AddPersonModel
#{ Layout = null; }
<div class="modal-content">
#using(Html.BeginForm("Add", "Person", FormMethod.Post))
{
<div class="modal-header">
<h4 class="modal-title">Add New Person</h4>
</div>
<div class="modal-body">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="row">
<div class="col-md-6">
#Html.TextBoxFor(m => m.FirstName)
</div>
<div class="col-md-6">
#Html.TextBoxFor(m => m.LastName)
</div>
</div>
<div class="row">
<div class="col-md-12">
#Html.TextBoxFor(m => m.Email)
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Create</button>
</div>
#Html.AntiForgeryToken()
}
</div>
PersonController.cs
namespace MyApp.Controllers
{
public class PersonController : Controller
{
public ActionResult Index()
{
var model = new IndexModel();
return View(model);
}
public ActionResult Add()
{
var model = new AddPersonModel();
return View(model);
}
[HttpPost]
public ActionResult Add(AddPersonModel model)
{
if (ModelState.IsValid)
{
model.Save();
}
else
{
// I'm stuck here.
}
var listModel = new IndexModel();
return View("~/Views/Person/Index.cshtml", listModel );
}
}
}
Everything works except for validation. If the user enters some invalid data, the view reloads the entire screen and the data is lost. The dialog is also closed. I need to be able to show the values the user entered and the validation summary in the dialog window if the data is invalid. Yet, I'm not sure how to do this.
I am trying to return the results of a table back to the controller for further manipulation. Once returned to the controller the value shows as null. In the past I have been able to use #Html.HiddenFor to return the values but it doesn't seem to be working in this instance. Not sure what I am doing wrong here. Any help is greatly appreciated.
#model IEnumerable<Project.Models.Item>
#{
ViewBag.Title = "Welcome to The Project";
}
#using (Html.BeginForm("UpdateQuality", "Home", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
<div class="row">
<div class="form-group">
<table class="table table-bordered">
<tr>
<th>#Html.DisplayNameFor(m => m.Name)</th>
<th>#Html.DisplayNameFor(m => m.SellIn)</th>
<th>#Html.DisplayNameFor(m => m.Quality)</th>
</tr>
#for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td>#Html.DisplayFor(m => m.ElementAt(i).Name)</td>
<td>#Html.DisplayFor(m => m.ElementAt(i).SellIn)</td>
<td>#Html.DisplayFor(m => m.ElementAt(i).Quality)</td>
#Html.HiddenFor(m => m.ElementAt(i).Name)
#Html.HiddenFor(m => m.ElementAt(i).SellIn)
#Html.HiddenFor(m => m.ElementAt(i).Quality)
</tr>
}
</table>
<div class="form-group">
<div style="margin-top: 50px">
<input type="submit" class="btn btn-primary" value="Advance Day"/>
</div>
</div>
</div>
</div>
}
And here is the controller which returns null.
public ActionResult UpdateQuality(List<Item> Items )
{
return View("Index", (object)Items);
}
You cannot use ElementAt() in a HtmlHelper method that generates form controls (look at the name attribute your generating - it does not match your model).
Either change the model to be IList<T>
#model List<Project.Models.Item>
and use a for loop
#for (int i = 0; i < Model.Count; i++)
{
....
#Html.HiddenFor(m => m.[i].Name)
....
or change use a custom EditorTemplate for typeof Item, and in the main view, use #Html.EditorFor(m => m) to generate the correct html for each item in the collection.
I want to render login page if user session is over, this is my code :
#model IEnumerable<LPDPWebApp.User>
#{
Layout = "~/Views/Shared/_LayoutDashboard.cshtml";
String datenow = DateTime.Now.ToShortDateString();
Boolean IsAuthorized = false;
if (Session["username"] != null)
{
IsAuthorized = true;
Layout = "~/Views/Shared/_LayoutDashboard.cshtml";
}
else
{
Layout = "~/Views/Shared/_LayoutLogin.cshtml";
}
}
#if (IsAuthorized)
{
<div class="side-b">
<div class="container-fluid">
<div class="row page-title">
<div class="col-md-12">
<button type="button" class="pull-right btn-layout-modal" id="modal-open" data-toggle="modal" data-target="#layout-modal">
<i class="fa fa-th fa-fw"></i>
</button>
<h4>Dana Kegiatan Pendidikan</h4>
<p>#datenow</p>
</div>
</div>
<div class="row grid-sortable">
Create
<table class="table">
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Username)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
#Html.ActionLink("Details", "Details", new { id = item.ID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.ID })
</td>
</tr>
}
</table>
</div>
</div>
</div>
}
else
{
#Html.Partial("_LoginPartial")
}
_LoginPartial.cshtml
#model LPDPWebApp.Models.Access.LoginModel
#using (Html.BeginForm("Login", "Access", FormMethod.Post, new { id = "formLogin", #class = "form-vertical" }))
{
#Html.AntiForgeryToken()
<div class="col-md-4">
#Html.TextBoxFor(m => m.Username, new { placeholder = "username", #class = "form-control", id = "tbxUsername" })
</div>
<div class="col-md-4">
#Html.PasswordFor(m => m.Password, new { placeholder = "password", #class = "form-control", id = "tbxPwd" })
</div>
<div class="col-md-8">
<button type="submit" class="btn btn-primary pull-right btn-submit">submit</button>
</div>
}
but i get error on #Html.Partial("_LoginPartial") :
The model item passed into the dictionary is of type
'System.Collections.Generic.List`1[LPDPWebApp.User]', but this
dictionary requires a model item of type
'LPDPWebApp.Models.Access.LoginModel'.
I just want to render _LoginPartial if Session is over, how to solve this problem?
Your _LoginPartial is expecting a model of type LoginModel:
#model LPDPWebApp.Models.Access.LoginModel
But when you're calling the #Html.Partial method:
#Html.Partial("_LoginPartial")
You don't specify any model hence the parent model (IEnumerable<LPDPWebApp.User>) is used and the exception is thrown because they don't match.
Try this:
#Html.Partial("_LoginPartial", new LoginModel());
It's also seems like you don't really use the model in your _LoginPartial, then you can even pass a null model to it:
#Html.Partial("_LoginPartial", null);
Ola.. I have a problem with editing of few models in table. I have a List of models on page (with foreach), something like
<table id="grid-table" >
#foreach (var image in ViewBag.Images)
{
<tr>
<td >
<a href="#Url.Action("ShowFullImage", new { id = #image.ID })" rel="lightbox[roadtrip]" title="#image.Description" >
<img src="#Url.Action("ShowImageThumbneil", new { id = #image.ID })" alt="#image.AlternateText" />
</a>
</td>
<td >
#using (Html.BeginForm("SaveImageInfo", "Admin", FormMethod.Post))
{
#Html.TextAreaFor(m => m.Description) <br />
#Html.TextBoxFor(m => m.AlternateText) <br />
#Html.LabelFor(m => m.ID)
<div id="item-post" >
<input title="Подтвердить" type="submit" value="Подтвердить" />
</div>
}
</td>
</tr>
}
and I want to have a way to edit ONE model item. In controller I have something like this:
[HttpPost]
public ActionResult SaveImageInfo(ImageModel imageModel)
{
Image img = _core.GetImageByID(_client, imageModel.ID);
img.AlternateText = imageModel.AlternateText;
img.Description = imageModel.Description;
_core.SaveImageInfo(_client, img);
return View();
}
but, of course, it's not works..
Can somebody help me?
Change #Html.LabelFor(m => m.ID) with #Html.HiddenFor(m => m.ID). Contents of labels are not sent with POST, but contents of hidden fields are..
I am guessing a bit, as I don't know exactly what problem you are seeing, but if it is to do with it trying to redirect, following the save, then try changing from:
Html.BeginForm
to
Ajax.BeginForm