I have a MVC model as follows
public class ListSampleModel
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int SampleId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IList<PointOfContact> lstPoc { get; set; }
}
public class PointOfContact
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int PocID { get; set; }
public string EmailAddress { get; set; }
public string PhoneNumber { get; set; }
}
What I have done is, create "PointOfContact" as a partial view on a jquery dialog and on "save" button click it shows the data on the main view in labels (I will have multiple point of contacts), now on submit I want this data along with the property values of ListSampleData to be posted back to the controller.
The issue is, the data related to simple properties are returned back but the list is always null.
below is my View
#model MVCDataFlowSample.Models.ListSampleModel
#using (Html.BeginForm("Create", "ListSample", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>ListSampleModel</legend>
<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>
<div id="dialog1" class="ui-dialog" style="background-color:gray;"></div>
<div id="data">
</div>
<p>
<input type="button" value="Add More..." id="btnAdd" />
</p>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Javascript on Main View
<script type="text/javascript">
$(document).ready(function () {
$('#btnAdd').on('click', function () {
$('#dialog1').dialog({
autoOpen: true,
position: { my: "center", at: "center", of: window },
width: 1000,
resizable: false,
title: 'Add User Form',
modal: true,
open: function () {
$(this).load('#Url.Action("PocPartial", "ListSample")');
},
buttons: {
"Save User": function () {
addUserInfo();
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
}
});
return false;
});
function addUserInfo(email, phone) {
var text = "<div id='EmailAddress'>Email Address:" + $("#EAddress").val() + "</div><div id='PhoneNumber'>Phone Number:" + $("#PhNo").val() + "</div>";
$("#data").append(text);
}
});
</script>
Partial View
#model MVCDataFlowSample.Models.PointOfContact
<div>
#Html.Label("EmailAddress:")
<div>
#Html.TextBoxFor(x => x.EmailAddress, new { id = "EAddress" })
</div>
#Html.Label("PhoneNumber:")
<div>
#Html.TextBoxFor(x => x.PhoneNumber, new { id = "PhNo" })
</div>
</div>
any help will be appreciated.
The contents of DIV elements are not submitted as form data. If you'd like that data to be submitted, add it to the DOM as hidden INPUT elements in addition to your DIVs. You'll also need to format their names correctly so that MVC knows how to bind them. See this article for how complex objects are bound in MVC.
I posted partial view data to the main page's post action You can modify the idea to any of your suits
Partial View
<select name="Country">
<option>Indian</option>
<option>Africa</option>
</select>
<select name="State">
<option>Kerala</option>
<option>TamilNadu</option>
</select>
<select name="City">
<option>Thrissur</option>
<option>Palakkad</option>
</select>
Index Page
#{
ViewBag.Title = "IndexTestPost";
}
<h2>IndexTestPost</h2>
#using(Html.BeginForm()){
#Html.Partial("~/Views/_PartialPagePostCountry.cshtml");
<input type="submit" />
}
Class To Catch Post Data
public class CountryCityState
{
public string Country { get; set; }
public string State { get; set; }
public string City { get; set; }
}
Controller
public class TestPostPartialController : Controller
{
// GET: TestPostPartial
public ActionResult IndexTestPost()
{
return View();
}
[HttpPost]
public ActionResult IndexTestPost(CountryCityState CtnCtySta)
{
return View();
}
}
Related
I've got a BeginCollectionItem repeater that is working perfectly, however when I try and follow the Joe Stevens blog to add nested lists it doesn't work in the way I expected.
I've used the BeginCollectionItemCore as I'm using AspNetCore, I've taken the code from here as it says it has the built in elements from the blog already in there: https://github.com/saad749/BeginCollectionItemCore
I have a main BeginCollectionItem called Section and a nested collection called SingleLine. I expected the code to output something like: Section[long-code-here].SingleLine[another-code-here].SingleLineTextBlock
however what I get is SingleLine[long-code-here].SingleLineTextBlock
I've included my code below;
Model:
namespace project.Models.SetupViewModels
{
public class SOPTopTemplateBuilderViewModel
{
public List<SectionViewModel> Section { get; set; }
}
public class SectionViewModel {
public int SectionId { get; set; }
public string SectionText { get; set; }
public string TopTempId { get; set; }
public List<SingleLineViewModel> SingleLines { get; set; }
}
}
Partial view:
#model project.Models.SetupViewModels.SectionViewModel
#using HtmlHelpers.BeginCollectionItemCore
<div class="new-section form-row">
#using (Html.BeginCollectionItem("Section"))
{
<div class="top-line">
<div class="col-12 col-md-11">
#Html.HiddenFor(m => m.SectionId, new { #class="id" })
#Html.EditorFor(m => m.SectionText, new { #class = "form-control limit-form"})
</div>
<div class="col-12 col-md-1">
</div>
</div>
}
<div class="main-row">
<div class="buttons-div">
<button id="add-single-line" type="button" data-containerPrefix="#ViewData["ContainerPrefix"]">Add Single Text</button>
</div>
</div>
<div class="main-row">
</div>
</div>
Ajax to add new line:
var form = $('form');
var recipients = $('.main-row');
$("#add-single-line").click(function(){
$.ajax({
type: "POST",
url: '#Url.Action("GetNewSingleLine")',
data: { "containerPrefix": recipients.data("containerPrefix") },
success: function (data) {
recipients.append(data);
}
});
});
EditorFor:
#model project.Models.SetupViewModels.SingleLineViewModel
#using HtmlHelpers.BeginCollectionItemCore
#using (Html.BeginCollectionItem("SingleLine"))
{
<div class="single-line-row">
#Html.HiddenFor(m => m.SingleLinkTextID, new { #class="id" })
#Html.TextBoxFor(m => m.SingleLinkTextBlock, new { #class = "form-control limit-form"})
</div>
}
EditFor Controller:
public ActionResult GetNewSingleLine(string containerPrefix)
{
ViewData["ContainerPrefix"] = containerPrefix;
return PartialView("SingleLineViewModel", new SingleLineViewModel());
}
I struggled with this exact issue for a while until I happened upon this post - which ended up leading me to an answer (thank you!).
In the example above, it is storing the prefix in the button.add-single-line but attempting to load it from the div.main-row so you probably are getting 'undefined' as the prefix. By pulling from the same item which cached the value, the code above will do what is intended.
i have the following controller that calls view with template that generates a set of checkboxes
The controller / Action
public class CompoundsController : Controller
{
//
// GET: /Compounds/
testdbDBContext db = new testdbDBContext();
public ActionResult Index()
{
var comps = db.Compounds.Select(e => new CompoundModel { Id=e.Id, Code=e.Code, Name=e.Name, IsSelected = e.IsSelected }).ToList();
return View(new ChemicalsVM { cModel = comps});
}
}
The view
#model mvca1.Models.ChemicalsVM
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>ChemicalsVM</legend>
<div class="editor-label">
#Html.LabelFor(model => model.SName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.SName)
#Html.ValidationMessageFor(model => model.SName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.DName)
#Html.ValidationMessageFor(model => model.DName)
</div>
<div class="editor-label">
#Html.Label("Chemicals")
</div>
<div class="editor-field">
#Html.EditorFor(x=>x.cModel)
#Html.ValidationMessageFor(model => model.cModel)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
the template is:
#model mvca1.Models.CompoundModel
#{
ViewBag.Title = "rmplCompoundDB";
}
#Html.HiddenFor(x=>x.Id)
#Html.HiddenFor(x=>x.Code)
#Html.CheckBoxFor(x=>x.IsSelected, (Model.IsSelected)? new {#checked="checked"}:null)
#Html.LabelFor(x=>x.Name)
when i ran the code instead of generating checkboxes with labels it displays the id numbers (that should be hidden)
here is the video of what happens https://youtu.be/1Z2fwfBgyn8
why it does not display the checkboxes as expected?
UPDATE:
here is my ChemicalsVM
public class ChemicalsVM
{
public int Id { get; set; }
public string SName { get; set; }
public string DName { get; set; }
public List<CompoundModel> cModel { get; set; }
public ChemicalsVM()
{
cModel = new List<CompoundModel>();
}
}
here is the CompoundModel class
public class CompoundModel
{
public int Id { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
The html being rendered means the ViewEngine is not finding the EditorTemplate. The template must be named the same as the class (i.e. CompoundModel.cshtml) and be located in either the /Views/Shared/EditorTemplates or /Views/Compounds/EditorTemplates folders.
by default MVC use jquery unobtrusive validation lib to show validation message at client side. suppose i have small form with two textbox for first name and last name. when click submit button then client side validation will fire and display all validation message at once. but i want to display validation message one by one. now tell me where to customize the code and what code need to add or modify in js to make it possible.
here is my small sample code
namespace MVC_myfirst_Mvcapplication.Models
{
public class Person
{
public int ID { get; set; }
[Required]
[StringLength(30)]
public string First { get; set; }
[Required]
[StringLength(30)]
public string Last { get; set; }
public DateTime Birthdate { get; set; }
}
public class PersonContext : DbContext
{
public DbSet<Person> People { get; set; }
}
}
Controller : PersonController.cs
public class PersonController : Controller
{
PersonContext db = new PersonContext();
//
// GET: /Person/
public ActionResult Index()
{
var People = db.People.ToList();
return View(People);
}
//
// GET: /Person/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Person/Create
[HttpPost]
public ActionResult Create(Person Person)
{
db.People.Add(Person);
db.SaveChanges();
return RedirectToAction("Index");
}
}
View:
#model MVC_myfirst_Mvcapplication.Models.Person
#{
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>Person</legend>
<div class="editor-label">
#Html.LabelFor(model => model.First)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.First)
#Html.ValidationMessageFor(model => model.First)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Last)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Last)
#Html.ValidationMessageFor(model => model.Last)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Birthdate)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Birthdate)
#Html.ValidationMessageFor(model => model.Birthdate)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
tell me which code i need to change in js to show validation message one-by-one in a specific div? thanks
I use jquery validation in my MVC application and after selecting and leaving an input, it is automatically validated. On the other hand, if user does not select an input, they are not validated even if submitting the form. So, I want to validate all the related fields after pressing submit button on MVC Razor page. How can I do this?
I created a simple example. It's just to give you a start, you still have to modify this code to your needs. This example is using jquery form validation.
Model
public class Vehicle
{
public int Id { get; set; }
public string Make { get; set; }
public string Model { get; set; }
}
Controller & Action
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
View
#model JqueryValidationDemo.Models.Vehicle
#{
ViewBag.Title = "Jquery Form Validation Demo";
}
<script src="~/Scripts/jquery-2.0.3.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script>
$(document).ready(function () {
$('#myform').validate({ // initialize the plugin
rules: {
Make: {
required: true,
minlength: 2
},
Model: { required: true }
},
messages: {
Make: {
required: "Make is required!",
minlength: "Make Name at least 2 characters long!"
},
Model: {
required: "Modl is required!"
}
},
submitHandler:
$("#myform").on('submit', function () {
if ($("#myform").valid()) {
//Do something here
alert("Validation passed");
}
return false;
})
})
});
</script>
#using (Html.BeginForm("Index", "Home", FormMethod.Get, new { #id = "myform" }))
{
<fieldset>
<legend>Vehicle</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Make)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Make)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Model)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Model)
</div>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
}
Note: Be careful with your jquery reference, you don't need to use jquery.validate.unobtrusive.js.
Hope it will give you a good start.
Update:
Remove keyup or keypress
Remove keypress
$("#youElementId").bind('keypress', function (e) {
if (e.keyCode == 13) {
return false;
}
return true;
});
I have a model with an object that contains a collection like this:
namespace API.Example.Models
{
public class OrderTest
{
public string UserName { get; set; }
public string Token { get; set; }
public POCO.Order Order { get; set; }
}
}
namespace Supertext.API.POCO
{
public class Order
{
public List<TranslationGroup> Groups = new List<TranslationGroup>();
}
public class TranslationGroup
{
public string GroupId { get; set; }
}
}
The Order object contains a collection called Groups.
In the view I display the collection like this (with the index like explained in several examples)
#Html.LabelFor(m => m.UserName)
#Html.TextBoxFor(m => m.UserName)
#for (int i = 0; i < Model.Order.Groups.Count; i++)
{
#Html.LabelFor(m => Model.Order.Groups[i].GroupId)
#Html.TextBoxFor(m => Model.Order.Groups[i].GroupId)
}
And this is the Controller method that gets called:
[HttpPost]
public ActionResult Index(Models.OrderTest model)
The HTML of the UserName element:
<input id="UserName" name="UserName" style="width:300px;" type="text" value="">
and the GroupId element:
<input id="Order_Groups_0__GroupId" name="Order.Groups[0].GroupId" type="text" value="1">
I can access the UserName, but there is nothing in the collection.
What am I missing?
And whats the difference between using m.UserName and Model.Order.Groups (I mean m and Model). Is that my issue?
Each property of POCO entity use like a property managed by the CLR. Let the CLR manage the create of instance and etc.. or you can generate conflicts that can throw issues like you have.
Change your Order code to this:
public class Order
{
public List<TranslationGroup> Groups { get; set; }
}
--EDIT
I create a new project and add the following class:
public class TranslationGroup
{
public string GroupId { get; set; }
}
public class Order
{
public List<TranslationGroup> Groups { get; set; }
}
public class OrderTest
{
public string UserName { get; set; }
public string Token { get; set; }
public Order Order { get; set; }
}
Here my code behind of the OrderTestController:
public ActionResult Index()
{
var orderTest = new Models.OrderTest()
{
UserName = "Vinicius",
Token = "12as1da58sd558",
Order = new Models.Order()
{
Groups = new List<Models.TranslationGroup>()
{
new Models.TranslationGroup() { GroupId = "a54s"},
new Models.TranslationGroup() { GroupId = "a87d"},
new Models.TranslationGroup() { GroupId = "2gf4"}
}
}
};
return View(orderTest);
}
[HttpPost]
public ActionResult Index(Models.OrderTest model)
{
return View();
}
And Index View:
#model TestCollection.Models.OrderTest
#{
ViewBag.Title = "Index";
}
<h2>
Index</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>OrderTest</legend>
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Token)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Token)
#Html.ValidationMessageFor(model => model.Token)
</div>
#for (int i = 0; i < Model.Order.Groups.Count; i++)
{
<div class="editor-label">
#Html.LabelFor(m => Model.Order.Groups[i].GroupId)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => Model.Order.Groups[i].GroupId)
</div>
}
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
So, if you run, and go to OrderTest view, you 'll see all attributes filled, and when you click in create, all things will be binded (the collection as well).