My MVC application has a classic parent-child (master-detail) relations.
I want to have a single page that create both the new parent and the children on the same page. I have added an action the returns a partial view that and adds the child HTML to the parent’s view, but I don’t know how to associate the newly created child in the action to the original parent (in other word, how to I add the new child entity to the collection of these entities in the parent entity).
I guess that when I submit the form the action should get the parent entity with the newly created children in its collection.
So to make things short, what should be the code of the action that creates the child entity and how is the child added to its parent collection?
I have read a lot of posts here (and other sites) and couldn’t find an example.
The application uses MVC 4 and Entity Framework 5.
Code sample (I removed some of the code the keep it simple).
The model is Form (parent) and FormField (child) entities.
public partial class Form
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<FormField> FormFields { get; set; }
}
public partial class FormField
{
public int ID { get; set; }
public string Name { get; set; }
public int FormID { get; set; }
}
The following partial view (_CreateFormField.cshtml) creates new FormField (child).
#model FormField
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>FormField</legend>
<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.FormID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FormID)
#Html.ValidationMessageFor(model => model.FormID)
</div>
</fieldset>
}
And the following view (Create.cshtml) is the one the creates the Form.
#model Form
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Form</legend>
<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>
#Html.ActionLink(
"Add Field",
"CreateFormField",
new { id = -1},
new { #class = "form-field" })
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
<div id="CreateFormField"></div>
#section Scripts {
<script>
$(function () {
$('.form-field').on('click', function (e) {
$.get($(this).prop('href'), function (response) {
$('#CreateFormField').append(response)
});
e.preventDefault();
});
});
</script>
#Scripts.Render("~/bundles/jqueryval")
}
The following actions handle the creation in the FormController.
[HttpPost]
public ActionResult Create(Form form)
{
if (ModelState.IsValid)
{
db.Forms.Add(form);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(form);
}
public ActionResult CreateFormField(string id = null)
{
// I guess something is missing here.
return PartialView("_CreateFormField", new FormField());
}
Thanks in advance,
Sharon.
I think the best and simplest way for you is that you have a view for creating Form and at the bottom of it put a fieldset to assign FormFields to it.
For the fieldset, you should have two partial views: One for create and another for edit. The partial view for creating should be something like this:
#model myPrj.Models.Form_FormFieldInfo
#{
var index = Guid.NewGuid().ToString();
string ln = (string)ViewBag.ListName;
string hn = ln + ".Index";
}
<tr>
<td>
<input type="hidden" name="#hn" value="#index" />
#Html.LabelFor(model => model.FormFieldID)
</td>
<td>
#Html.DropDownList(ln + "[" + index + "].FormFieldID",
new SelectList(new myPrj.Models.DbContext().FormFields, "ID", "FieldName"))
</td>
<td>
<input type="button" onclick="$(this).parent().parent().remove();"
value="Remove" />
</td>
</tr>
By calling this partial view in the create place view ajaxly, you can render some elements for each tag. Each line of elements contains a label, a DropDownList containing tags, and a remove button to simply remove the created elements.
In the create place view, you have a bare table which will contain those elements you create through the partial view:
<fieldset>
<legend>Form and FormFields</legend>
#Html.ValidationMessageFor(model => model.FormFields)</label>
<table id="tblFields"></table>
<input type="button" id="btnAddTag" value="Add new Field"/>
<img id="imgSpinnerl" src="~/Images/indicator-blue.gif" style="display:none;" />
</fieldset>
and you have the following script to create a line of elements for each tag:
$(document).ready(function () {
$("#btnAddField").click(function () {
$.ajax({
url: "/Controller/GetFormFieldRow/FormFields",
type: 'GET', dataType: 'json',
success: function (data, textStatus, jqXHR) {
$("#tblFields").append(jqXHR.responseText);
},
error: function (jqXHR, textStatus, errorThrown) {
$("#tblFields").append(jqXHR.responseText);
},
beforeSend: function () { $("#imgSpinnerl").show(); },
complete: function () { $("#imgSpinnerl").hide(); }
});
});
});
The action method GetFormFieldRow is like the following:
public PartialViewResult GetFormFieldRow(string id = "")
{
ViewBag.ListName = id;
return PartialView("_FormFieldPartial");
}
and your done for the create... The whole solution for your question has many codes for views, partial views, controllers, ajax calls and model binding. I tried to just show you the way because I really can't to post all of them in this answer.
Here is the full info and how-to.
Hope that this answer be useful and lead the way for you.
You can use #Html.RenderPartial(_CreateFormField.cshtml) htlper method inside your parent cshtml page.
For mode info, http://msdn.microsoft.com/en-us/library/dd492962(v=vs.118).aspx
I am providing an pseudo code example,
#Foreach(childModel in model.FormFields)
{
#Html.RenderPartial("childView.cshtml","Name", childModel)
}
Please try it in proper c# syntactical way and you will get your partial views rendered for each collection item.
The problem is that your partial view needs to use:
#model Form //Instead of FormField
and then inside of the partial view you must use model => model.FormField.x
<div class="editor-label">
#Html.LabelFor(model => model.FormField.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FormField.Name)
#Html.ValidationMessageFor(model => model.FormField.Name)
</div>
This only works for one-to-one relationships (or so I read in this thread: Here). It also does not matter if you have #Html.Form inside of the partial view.
After making those changes I had no problem getting all of the posted data back to the controller.
EDIT: I've run into problems with this as anyone would soon figure out.
The better way to do this (that I've seen) is instead use an EditorTemplate. This way the editor stays independent of the Parent, and you can add a Form on any page, not simply a page where you are also adding a FormField.
You would then replace
#Html.Partial("view")
with
#Html.EditorFor()
Basically, I've found out that it's far better to use an #Html.EditorFor instead of a partial view when doing editing (It is called a view - not an editor).
If you want to use grid based layout you may want to try Kendo UI grid
Use jQueryto add FormField on click of button.
Similar I've used it as follows
<div class="accomp-multi-field-wrapper">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>FormId</th>
<th>Remove</th>
</tr>
</thead>
<tbody class="accomp-multi-fields">
<tr class="multi-field">
<td> <input name="FormFields[0].Name" type="text" value=""></td>
<td> <input name="FormFields[0].FormId" type="text" value=""></td>
<td> <button type="button" class="remove-field">X</button></td>
</tr>
</tbody>
<tr>
<th><button type="button" class="add-field btn btn-xs btn-primary addclr"><i class="fa fa-plus"></i> Add field</button> </th>
</tr>
</table>
</div>
and jQuery is as follows for adding field and removing
<script>
$('.accomp-multi-field-wrapper').each(function () {
var $wrapper = $('.accomp-multi-fields', this);
$(".add-field", $(this)).click(function (e) {
var $len = $('.multi-field', $wrapper).length;
$('.multi-field:first-child', $wrapper).clone(false, true).appendTo($wrapper).find('select,input,span').val('').each(function () {
$(this).attr('name', $(this).attr('name').replace('\[0\]', '\[' + $len + '\]'));
});
$(document).on("click",'.multi-field .remove-field', function () {
if ($('.multi-field', $wrapper).length > 1) {
$(this).closest('tr').remove();
//
$('.multi-field', $wrapper).each(function (indx) {
$(this).find('input,select,span').each(function () {
$(this).attr('name', $(this).attr('name').replace(/\d+/g, indx));
})
})
}
});
</script>
Hope so this is going to help you.
Related
The following code works as I need it to:
#using (Html.BeginForm("LOLOL", "PATIENT", null))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>PATIENT</legend>
<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>
</fieldset>
<p>
<input type="submit" value="SUBMIT" />
</p>
}
In LOLOLController:
[HttpPost]
public IActionResult LOLOL(Patient p) {
var client = new MongoClient("mongodb://localhost:27017");
var userId = _userManager.GetUserId(HttpContext.User);
string db_name = "test" + userId;
var database = client.GetDatabase(db_name);
var collection = database.GetCollection<BsonDocument>("patients");
var filter = Builders<BsonDocument>.Filter.Eq("Name", p.Name.ToString());
var document = collection.Find(filter).First();
// I'm cutting short the rest of the code, because when I do something
// similar later, "collection.Find(filter).First()" fires an exception, I'll
// explain..
return View(p);
}
I have something equivalent to taking off the fieldset element in the HTML, leaving basically just a button in the "Html.BeginForm", but then the data is clearly not binding properly, which I know because if I just have a button and no data-entry, I click the button and then I get an error saying the data cannot be found from the database. (EDIT: I now have confirmed that this is indeed because the Patient object is not being passed to the controller quite as I expected it to, seems like a brand new Patient object was created upon calling html.beginform ... I thought that maybe the old Patient object was being passed so I did not have to enter all its data members every time we use Html.BeginForm)
In sum, I want to fill out a text box, click a button to load a new page and display the value of that textbox, but have that value also persisted in essentially a session state, so that if I call another Html.BeginForm function and go into a third view, the text from the first view will be displayed in the third view, even though I did not have to type its value in the second view. Hopefully I can repeat this process, and essentially load up the data members of a class with one view per data member.
Make sure you pass the data from the previous view to the new view from your Controller. When you pass it, include #HiddenFor for those properties from the previous view in your new view. That way the new view will keep and then pass the values to your next POST.
#Html.HiddenFor(model => model.PropertyYouPassedAndWantToKeepAndPassAgain
Edit: Here's the logic for using multiple views for one object... as requested.
Model:
public class Patient
{
string Name { get; set; }
string Address { get; set; }
string City { get; set; }
}
Page1 GET:
[HttpGet]
public ActionResult Page1()
{
Patient patient = new Patient();
return View("~/Views/Page1.cshtml", patient);
}
Page 1 View... only ask for the name.
#model mysite.Models.Patient
#using (Html.BeginForm("LOLOL", "PATIENT", null))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>PATIENT</legend>
<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>
</fieldset>
<p>
<input type="submit" value="SUBMIT" />
</p>
}
Page1 POST... get the patient and pass it on to the next view...
[HttpPost]
public ActionResult Page1(Patient patient)
{
if (ModelState.IsValid)
{
return View("~/Views/Page2.cshtml", patient); // pass your patient to the second page view with the name
}
else
{
return View("~/Views/Page1.cshtml", patient);
}
}
Page2 GET... get the patient from the prior Page1 POST and send it off to the Page2 View.
[HttpGet]
public ActionResult Page2(Patient patient)
{
// Receive patient from Page1 post and pass it to new view... includes the name
return View("~/Views/Page2.cshtml", patient);
}
Page2 View gets the object... use a HiddenFor to keep the name which you just sent from the GET.
#model mysite.Models.Patient
#using (Html.BeginForm("LOLOL", "PATIENT", null))
{
#Html.HiddenFor(model => model.Name) #* This will keep the name on your next post *#
#Html.ValidationSummary(true)
<fieldset>
<legend>PATIENT</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Address)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Address)
#Html.ValidationMessageFor(model => model.Address)
</div>
</fieldset>
<p>
<input type="submit" value="SUBMIT" />
</p>
}
Since the HiddenFor holds the Name, it will be passed on your next post. It is there but hidden from the form itself.
[HttpPost]
public ActionResult Page2(Patient patient)
{
// Because of the HiddenFor, the Name will be passed because it was kept in the view... but hidden from the form itself.
// It's basically storing it for you to pass again
if (ModelState.IsValid)
{
// Pass object with Name and Address to next controller
return View("~/Views/Page3.cshtml", patient);
}
else
{
return View("~/Views/Page2.cshtml", patient);
}
}
Page2 POST
[HttpPost]
public ActionResult Page2(Patient patient)
{
// Because of the HiddenFor, the Name will be passed because it was kept in the view... but hidden from the form itself.
// It's basically storing it for you to pass again
if (ModelState.IsValid)
{
// Pass object with Name and Address to next controller
return View("~/Views/Page3.cshtml", patient);
}
else
{
return View("~/Views/Page2.cshtml", patient);
}
}
Page3 GET
[HttpGet]
public ActionResult Page3(Patient patient)
{
// Pass patient again... to your next view
return View("~/Views/Page3.cshtml", patient);
}
Page3 View...
#using (Html.BeginForm("LOLOL", "PATIENT", null))
{
#Html.HiddenFor(model => model.Name) #* Keep name again for your next post *#
#Html.HiddenFor(model => model.Address) #* Now we are keeping the address as well *#
#Html.ValidationSummary(true)
<fieldset>
<legend>PATIENT</legend>
<div class="editor-label">
#Html.LabelFor(model => model.City)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.City)
#Html.ValidationMessageFor(model => model.City)
</div>
</fieldset>
<p>
<input type="submit" value="SUBMIT" />
</p>
}
And so on and so forth... until you have your model complete and want to do something with it.
I have an ASP.NET MVC4 application where I'm allowing users to add 1 to many records on the client using javascript templates. It's working fine and using the right naming convention, the model binding is correctly transforming the post data into the desired collection of objects for the action method.
My question is, is there any way to use the built in MVC validation for records added using this approach. I've added data annotation attributes to my model but because I'm generating the html for each new record on the client I can't use the html helpers that typically make the process work.
Obviously, I can just add the client side validation myself and let the data annotations validate on the server but I'm wondering if there's a way to take advantage of the built in validation stack for this type of approach so I can maintain all my validation logic on the server.
For example:
The View has two form:form1 and form2。
The form1 has two part.
The first part:
There are two textbox and a Create button and a Save button.
The second part:
There are a .
so, when we fill in two textbox and press the Create button, if not pass validation, then show error messages.
if pass validation, then insert values into the and insert values to the form2.
[HttpPost] Action Create has a parameter List models.
when we press the Save button, will take values of form2 to controller mapping to List models.
Model
public class HomeModel
{
[Required]
public string Name { get; set; }
[Required]
public string Number { get; set; }
}
Controller:
[HttpPost]
public ActionResult Create(List<HomeModel> models)
{
// TODO: Add insert logic here
}
View:
#model MvcApplication1.Models.HomeModel
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm("Create", "Home", FormMethod.Post, new { id = "form1" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>HomeModel</legend>
<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.Number)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Number)
#Html.ValidationMessageFor(model => model.Number)
</div>
<p>
<input type="submit" value="Create" id="btnCreate" />
<input type="button" value="Save" id="btnSave" />
</p>
</fieldset>
<table id="tb"></table>
}
<div id="FormInfo" style="display: none;">
<form action="/Home/Create" id="form2" method="post"></form>
</div>
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
$(function () {
$("#form1").submit(function () {
var ErrorLength = $(".field-validation-error").length;
if (ErrorLength <= 0) {
var nameValue = $("#Name").val();
var numberValue = $("#Number").val();
InsertToForm2(nameValue, numberValue);
InsertToTable(nameValue, numberValue);
}
return false;
});
$("#btnSave").click(function () {
$("#form2").submit();
});
});
function InsertToForm2(nameValue, numberValue) {
var inputCount = $("#form2 input").length / 2;
var combineHTML = "<input type='text' name='models[" + inputCount + "].Name' value='" + nameValue + "' /> ";
combineHTML += "<input type='text' name='models[" + inputCount + "].Number' value='" + numberValue + "'/> ";
$("#form2").append(combineHTML);
}
function InsertToTable(nameValue, numberValue) {
var combineHTML = "<tr><td>" + nameValue + "</td><td>" + numberValue + "</td></tr>";
$("#tb").append(combineHTML);
}
</script>
}
Example Download
I follow this example to make n to n relations
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/updating-related-data-with-the-entity-framework-in-an-asp-net-mvc-application
it work fine but for the n to n relations with payload to the database i figure out and I can do the [HttpGet] and show the view what i want to show but now i want to know how can i get the textbox I have in my view, I can get the checkbox in my controller (see see below the action) and this is my view so my question will be how can get the textbox too? in my controller for every checkbox?
#using (Html.BeginForm("AgregarEmpresas", "Empleado"))
{
<fieldset>
<div class="editor-field">
<table>
<tr>
#{
int cnt = 0;
List<ITCOrganigrama.ViewModel.AsignarEmpresa> empresas = ViewBag.Empresas;
foreach (var empresa in empresas)
{
if (cnt++ % 5 == 0) {
#: </tr> <tr>
}
#: <td>
<input type="checkbox"
name="selectedEmpresa"
value="#empresa.EmpresaId"
#(Html.Raw(empresa.Assigned ? "checked=\"checked\"" : "")) />
#empresa.Nombre
<div>
#Html.LabelFor(model => empresa.cargo)
#Html.TextBoxFor(model => empresa.cargo, new { style = "width: 150px;" })
#Html.ValidationMessageFor(model => empresa.cargo)
</div>
#:</td>
}
#: </tr>
}
</table>
</div>
<p>
<input type="submit" value="Agregar" />
</p>
</fieldset>
}
the action where i get the chekbox
[HttpPost]
public ActionResult AgregarEmpresas(int? id, FormCollection formCollection, string[] selectedEmpresa)
{
}
my final view:
http://s3.subirimagenes.com:81/otros/previo/thump_7406511add1.jpg
http://www.subirimagenes.com/otros-add1-7406511.html
Edited:
ViewModel Class
public class AsignarEmpresa
{
public int EmpresaId { get; set; }
public string Nombre { get; set; }
public string cargo { get; set; }
public bool Assigned { get; set; }
}
Look at your post action and it's parameters. Names of those are really important.
Your checkboxes
<input type="checkbox"
name="selectedEmpresa"
value="#empresa.EmpresaId"
are working fine beacuse look at the name of the input its "selectedEmpresa" it's the same name as in Controller Action definition. Model binder looks for this name in posted data and if he finds it, he creates object from it. In your case he will try to parse data into string[] object.
So ... first of all you have to change action definition to something like.
[HttpPost]
public ActionResult AgregarEmpresas(int? id, FormCollection formCollection, string[] selectedEmpresa,string [] empresaTextBox)
{
}
Then you have to change generated html.
#Html.TextBoxFor(model => empresa.cargo, new { style = "width: 150px;", name="empresaTextBox" })
With those changes you should get some data inside Action. However you will get something weird beacuse you have multiple checkboxes and textboxes in order to tell model binder that there are multiple elements of those you have to prepare special name of inputs that contains index number.
Look at this example
<input name="childs[0]"></input>
<input name="childs[1]"></input>
In this case Model Binder will create array of objects that contains 2 of them.
So finally your code would have to look like this.
#using (Html.BeginForm("AgregarEmpresas", "Empleado"))
{
<fieldset>
<div class="editor-field">
<table>
<tr>
#{
int cnt = 0;
int i=0;
List<ITCOrganigrama.ViewModel.AsignarEmpresa> empresas = ViewBag.Empresas;
foreach (var empresa in empresas)
{
if (cnt++ % 5 == 0) {
#: </tr> <tr>
}
#: <td>
<input type="checkbox"
name="selectedEmpresa[#i]"
value="#empresa.EmpresaId"
#(Html.Raw(empresa.Assigned ? "checked=\"checked\"" : "")) />
#empresa.Nombre
<div>
#Html.LabelFor(model => empresa.cargo)
#Html.TextBoxFor(model => empresa.cargo, new { style = "width: 150px;" ,name=String.Format("empresaTextBox\[{0}\]",i) })
#Html.ValidationMessageFor(model => empresa.cargo)
</div>
#:</td>
i++;
}
#: </tr>
}
</table>
</div>
<p>
<input type="submit" value="Agregar" />
</p>
</fieldset>
}
If you will get this to work. Then i would try to create a class with one boolean and one string value. With this change you would operate on the array of classes instead of two arrays with strings.
I have a simple ASP.NET MVC 3 site, from my Controller out of the Edit Action I pass a Object (a class which is also mapped by nhibernate)
After editing and clicking save i pass it to the [HTTPPost] decoraded Method but and all properties are correct, excerpt the "id" property it hat a guid value equivalent to NULL (00000000-0000-000...).
Is there a problem using the Domain Model to strongly type my Views? May the problem be that Id has:
{get; private set;}
???
Thanks in advance.
Here The Code:
My View:
'#model fnh.DataModel.Kunde
#{
View.Title = "EditKunde";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>EditKunde</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Fields</legend>
#Html.EditorFor(model => model._id)
#Html.EditorFor(model => model._KdNr);
<div class="editor-label">
#Html.LabelFor(model => model._Name)
`enter code here` </div>
<div class="editor-field">
#Html.EditorFor(model => model._Name)
#Html.ValidationMessageFor(model => model._Name)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
'
My Controller Actions:
' public ActionResult EditKunde(Guid id)
{
return View(_kunden.GetKundeById(id));
}
[HttpPost]
public ActionResult EditKunde(Kunde kunde)
{
Ansprechpartner anp = new Ansprechpartner();
anp._Name = "JustATry";
kunde._Ansprechpartner.Add(anp);
`enter code here` _kunden.EditKunde(kunde);
return View();
}'
Are you adding the Id property to your form (maybe as a hidden field)?
It would be useful if you post the Action code (for both Edit Actions), and the View.
Yo
I have a registration page on my site - at the top of the page is a login form for existing users. In the main area there is the registration form.
The login are is a partial view with #model ViewModels.LoginViewModel
The registration are is also a partial with #model ViewModels.RegViewModel
The main page which houses these partials is a view with #model ViewModels.RegPageViewModel
This viewmodel looks like:
public class RegViewModel
{
public RegisterVm RegisterVm { get; set; }
public LoginVm LoginVm { get; set; }
}
When I submit the registration part of the page (it's action is register/capture - the receiving action expects a RegisterVm) to it's controller it complains about being passed the wrong viewmodel
What's the deal with subviews and their viewmodel? Is there a standard approach to dealing with this?
Should I have one submit URL for this page which figures out if it's a login request or a register request and then handles the post accordingly? That seems messy to me though...
http://monobin.com/__d33cf45a4 - RegisterVm.cs (LoginVm.cs is pretty much the same as this)
http://monobin.com/__m69132f76 - RegPageVm.cs
Register.cshtml:
#model xxxx.ViewModels.RegPageVm
#{
View.Title = "Register";
Layout = "~/Views/Shared/_BareBones.cshtml";
}
<link rel="stylesheet" href="#Url.Content("~/Public/Css/signup.css")" type="text/css" />
<div id="sign-up-container">
<div id="sign-up-box">
<div id="sign-up-box-left">
<img src="#Url.Content("~/Public/Images/Signup_176x81.png")" />
</div>
<div id="sign-up-box-right">
#Html.Partial("_Register")
</div>
</div>
</div>
<div class="clear">
</div>
_Register.cshtml:
#model xxxx.ViewModels.RegisterVm
#using (Html.BeginForm("Capture", "Register", FormMethod.Post))
{
<table class="sign-up-box-inner">
<tr>
<td class="label-area">
#Html.LabelFor(x => x.Email)
</td>
<td class="field-area">
#Html.TextBoxFor(x => x.Email, new { #class = "login-input", title = "Enter Name" })
</td>
</tr>
<tr>
<td class="label-area">
#Html.LabelFor(x => x.Password)
</td>
<td class="field-area">
#Html.PasswordFor(x => x.Password, new { #class = "login-input", title = "Enter Name" })
</td>
</tr>
<tr>
<td class="label-area">
#Html.LabelFor(x => x.UserName)
</td>
<td class="field-area">
#Html.TextBoxFor(x => x.UserName, new { #class = "login-input", title = "Enter Name" })
</td>
</tr>
<tr>
<td colspan="2">
<input type="image" src="../../Public/Images/Submit_150x47.png" class="submit-button" />
</td>
</tr>
</table>
#Html.AntiForgeryToken()
}
And finally RegisterController.cs:
public class RegisterController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Capture(RegisterVm registerVm)
{
if (!ModelState.IsValid)
{
return View("index", new RegPageVm()
{
LoginVm = new LoginVm(),
RegisterVm = registerVm
});
}
return RedirectToAction("index", "Event");
}
}
w://
You need to ensure that the form elements (like the textbox etc) should have the same id as the RegisterVM and LoginVM properties. Your theory is right but I think you might be making a mistake in the naming convention of MVC.
If you can share your view code + the VM classes, then we'll be able to help better.
EDIT:
Looking at your code I think you should be passing the view model to your partial view. Like for example the following line believe should be like this >
#Html.Partial("_Register", Model.RegisterVm)
According to your answer to nEEbz:
You are using:
Html.TextBoxFor(x=>x.LoginVM.Email) // i guess
this would turn into <input name="LoginVM.Email" ...>
Notice the LoginVM. part
Your login action probably looks like:
public ActionResult Login(LoginVM model) { }
so it expect field names like Email and Password, not LoginVM.Email and LoginVM.Password.
So you could could use Html.Textbox instead (so that the field name doesn't get autocreated).