When I first load the page both my date textboxes are failing validation.
This appears to be because the two Date properties are set as required but are null.
My goals are to:
1) Have a model to pass into the controller that contains the criteria to search for.
2) That criteria will get reloaded when the page returns along with the results.
3) When the page 1st loads it will set the dates to a default to DateTime.Now and NOT show any results. When you submit the criteria it will then show results on next page load.
// Model
public class SearchModel
{
public long? StudentId { get; set; }
[Required]
public DateTime? Date1 { get; set; }
[Required]
public DateTime? Date2 { get; set; }
public List<string> Students { get; set; }
}
// View
#model SearchModel
<div>
#using (Html.BeginForm("StudentSearch", "Student", FormMethod.Post))
{
<span>
Date 1 #Html.TextBoxFor(m => m.Date1)
Date 2 #Html.TextBoxFor(m => m.Date2)
<input type="submit" value="Search" />
</span>
}
</div>
<div>
#foreach(var s in model.Students)
{ <span>#s</span> }
</div>
// Controller
[HttpGet]
public ActionResult StudentSearch(SearchModel model)
{
if (model.Date1 == null || model.Date2 == null)
{
model.Date1 = DateTime.Now;
model.Date2 = DateTime.Now;
}
return View();
}
Date time input is very sensitive. User could make a typo and ModelBinder won't be able to bind it to parameter. So, I suggest you to use framework like jQuery UI Datepicker or Kendo Datepicker.
public class StudentController : Controller
{
[HttpGet]
public ActionResult StudentSearch(SearchModel model)
{
if (model.Date1 == null || model.Date2 == null)
{
model.Date1 = DateTime.Now;
model.Date2 = DateTime.Now;
}
return View(model); <=====
}
[HttpPost]
public ActionResult StudentSearchPost(SearchModel model)
{
if (ModelState.IsValid)
{
// Do something
}
return View();
}
}
View
#model DemoWebMvc.Models.SearchModel
<div>
#using (Html.BeginForm("StudentSearchPost", "Student", FormMethod.Post))
{
<span>
Date 1 #Html.TextBoxFor(m => m.Date1)
Date 2 #Html.TextBoxFor(m => m.Date2)
<input type="submit" value="Search"/>
</span>
}
</div>
From Comment: I'm using a datetime picker control. Since the model
defaults to NULL since it's a DateTime? the very first page load shows
my date time fields failing validation. They're not failing because
what the user selects is invalid
The problem is you pass invalid model to View at Page Load, and default model binder tries to bind to model instance and it triggers validation error at Page Load.
If you do not have valid model, you should not send it to view at Page Load to avoid displaying validation error.
public class StudentController : Controller
{
[HttpGet]
public ActionResult StudentSearch()
{
return View();
}
[HttpPost]
public ActionResult StudentSearch(SearchModel model)
{
if (ModelState.IsValid)
{
}
return View(model);
}
}
View
#model DemoWebMvc.Models.SearchModel
#{
Layout = null;
}
#using (Html.BeginForm("StudentSearch", "Student", FormMethod.Post))
{
#Html.ValidationSummary(true)
<span>
Date 1 #Html.TextBoxFor(m => m.Date1)
#Html.ValidationMessageFor(m => m.Date1)<br />
Date 2 #Html.TextBoxFor(m => m.Date2)
#Html.ValidationMessageFor(m => m.Date2)<br />
<input type="submit" value="Search" />
</span>
}
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<script>
$(function () {
$("#Date1").datepicker();
$("#Date2").datepicker();
});
</script>
Just changing the type from DateTime? to DateTime should accomplish what you want. You can set the value to DateTime.Now in the first action or leave it as the default unsigned. Either will work in the view.
Edit: Here's what I mean in a dotnetfiddle: https://dotnetfiddle.net/Ei0LeQ
Related
First off, let me say that I'm new to MVC so if something seem strange then that's why. I probobly don't have the right aproach so I would like some guidelines
I have a form from which the user is suppose to enter translations to a page. The translations are handled as a list of TranslationObjects to the page object. I need a way to render input fields in the form for each language branch represented on the site and let the user fill those out and post them back to the controller.
This example is just a simplification of a more complex model, but it explains the problem pretty well.
The viewmodel:
public class Page
{
public List<TranslationObject> Translation { get; set; }
}
public class TranslationObject
{
public string LanguageBranch { get; set; }
public string PageName { get; set; }
public string PageDescription { get; set; }
}
Controller for rendering the form:
public ActionResult AddPage()
{
var model = new Page {Translation = new List<TranslationObject>()};
foreach (var languageBranch in new[] {"en", "sv", "de"}) // These are normally loaded from database
{
model.Translation.Add(new TranslationObject{ LanguageBranch = languageBranch});
}
return View(model);
}
View:
#model MvcApplication1.Models.Page
#using (Html.BeginForm("SubmitPage", "Home", FormMethod.Post))
{
foreach (var translation in Model.Translation)
{
#Html.LabelFor(x => x.Translation.FirstOrDefault(y => y.LanguageBranch == translation.LanguageBranch).PageName)
#Html.TextBoxFor(x => x.Translation.FirstOrDefault(y => y.LanguageBranch == translation.LanguageBranch).PageName)<br/>
#Html.LabelFor(x => x.Translation.FirstOrDefault(y => y.LanguageBranch == translation.LanguageBranch).PageDescription)
#Html.TextBoxFor(x => x.Translation.FirstOrDefault(y => y.LanguageBranch == translation.LanguageBranch).PageDescription)
}
<input type="submit" value="Submit"/>
}
And controller for the post:
[HttpPost]
public ActionResult SubmitPage(Page model)
{
// Save model to db
return View();
}
The translation object of the Page model is always null. I'm aware that this is probobly the wrong aproach so I'm asking for some direction to render a list of objects and returning them to the controller when posting
Use for instead of foreach.
#model MvcApplication1.Models.Page
#using (Html.BeginForm("SubmitPage", "Home", FormMethod.Post))
{
for(int i=0;i<Model.Translation.Count;i++)
{
#Html.LabelFor(x => x.Translation[i].PageName)
#Html.TextBoxFor(x => x.Translation[i].PageName)<br/>
#Html.LabelFor(x => x.Translation[i].PageDescription)
#Html.TextBoxFor(x => x.Translation[i].PageDescription)
}
<input type="submit" value="Submit"/>
}
And in Page Constructor initialize the Translation
We have a list of action links
Partial View
#foreach (var item in Model.Regions) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.RegionName)
</td>
<td>
<input type="submit" value="Select" />
</td>
#Html.HiddenFor(modelItem => Model.Id)
</tr>
}
</table>
I assume that this isn't the correct way to do this, but if you could point me in the right direction it would be appreciated. I want to submit this data into an existing form
Region View
#using (Html.BeginForm()){
<fieldset>
#Html.Partial("_RegionsPartial");
<legend>Create new region</legend>
<ol>
<li>#Html.LabelFor(m => m.RegionName)</li>
<li>#Html.EditorFor(m => m.RegionName)</li>
</ol>
<input type="submit" value="Next" />
#Html.HiddenFor(model => model.RegionId)
</fieldset>
}
So you can either submit a new one or submit an existing one. Im not sure how to get the id of an existing one into my model. Here is the controller:
public ActionResult Region()
{
var model = new WizardModel();
var getRegions = _facade.FetchRegion();
model.Regions = getRegions;
return View(model);
}
[HttpPost]
public ActionResult Region(WizardModel model)
{
if (model.RegionName != null)
{
var newRegion = _facade.CreateRegion(model.RegionName);
model.RegionId = newRegion.Id;
}
else
{
model.RegionName = _facade.FetchRegion(model.RegionId).RegionName;
}
TempData["suburbModel"] = model;
return RedirectToAction("Suburb");
}
Thanks for taking the time
So heres my example of passing an instance of a model. I've got a view with many courses so I need to click a button and fire an action, thus carrying all data (including relevant ID) of the course clicked. So in the end I carry the instance I need with the hidden fields.:)
My course model...
public class CourseModel
{
public int RecordId { get; set; }
public string StudentNameField { get; set; }
public string SubjectField { get; set; }
public string CatalogField { get; set; }
public string SectionField { get; set; }
public string InstrNameField { get; set; }
public string MtgStartField { get; set; }
public string MtgEndField { get; set; }
}
My main View...Called "CourseList" in Views folder
<div id="container">
<div class="selectLabel">Select a Course:</div><br />
#foreach (var item in Model)
{
#Html.DisplayFor(model=>item)
}
</div>
My Display template - Its a view called "CourseModel" in Shared\DisplayTemplates ...For your display template, you could make a unique model for existing & new. Using your "existing" model in the displaytemplate, it results in multiple forms, each using a button type=submit to submit the form with model instance. Use CSS to model the button like a link. If you still need to use actionlink, carry the iD as one of the params.
#using LecExamRes.Helpers
#model LecExamRes.Models.SelectionModel.CourseModel
#using (Html.BeginForm("CourseList", "Home", null, FormMethod.Post))
{
<div class="mlink">
#Html.AntiForgeryToken()
#Html.EncryptedHiddenFor(model => model.RecordId)
#Html.EncryptedHiddenFor(model => model.CatalogField)
#Html.EncryptedHiddenFor(model => model.SectionField)
#Html.EncryptedHiddenFor(model => model.SubjectField)
#Html.EncryptedHiddenFor(model => model.InstrNameField)
#Html.EncryptedHiddenFor(model => model.MtgStartField)
#Html.EncryptedHiddenFor(model => model.MtgEndField)
<p>
<input type="submit" name="gbtn" class="groovybutton" value="#Model.SubjectField - #Model.CatalogField - #Model.SectionField : #Model.InstrNameField">
</p>
</div>
}
My controller, Courselist [POST] Action...
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult CourseList(SelectionModel.CourseModel model)
{
//....do something with my model
}
I'm trying to use Ajax.BeginForm. I want to send a DateTime through a html form.
The problem is in the controller the Datetime is not initialised. I get the default DateTime. Any idea ? Thanks for your help.
My Model:
public class TestModel
{
public ObjectId _id { get; set; }
public DateTime myDate { get; set; }
}
My Action in TestController
[HttpPost]
public void UpdateTest(TestModel tmp)
{
tmp.myDate.Date <-- get the wrong date
...
...
}
My View
#model Project.Models.TestModel
#using (Ajax.BeginForm(new AjaxOptions()
{
HttpMethod = "POST",
Url = Url.Action("UpdateTest", "Test")
}))
{
#Html.TextBoxFor(model => model._id)
#Html.TextBoxFor(model => model.myDate) // example : 18/05/2013 17:00:00
<input type="submit" value="Submit" />
}
Javascript
<script type="text/javascript" src="/Scripts/jquery.unobtrusive-ajax.min.js">
</script>
You must create custom model binder for DateTime and register it on global.asax
I have a textbox in which the user can enter their desired username and save it. Once they save it and they happen to revisit their profile page that textbox should be populated with the last username they saved to display and the user will still have the ability to change it and resave. I am fairly new to this and not sure how to start this properly. I am using vs 2012 asp.net mvc 4 c#. Here is my code so far:
#model School.Models.StudentNameModel
#using (Html.BeginForm("_StudentNamePartial", "Profile")) {
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<fieldset>
<ol>
<li>
#Html.LabelFor(m => m.StudentName)
#Html.DisplayFor(m => m.StudentName)
#Html.TextBoxFor(m=>m.StudentName)
<button type="button" value="save" />
</li>
</ol>
</fieldset>
}
This is my Model:
public class StudentNameModel
{
[Display(Name = "Student Name")]
public string StudentName{ get; set; }
}
My controller:
GET - To get the student name from database if one exists.
[HttpPost]
public ActionResult _StudentNamePartial(int id)
{
id = WebSecurity.CurrentStudentId;
var model = new StudentNameModel();
using (var db = new StudentsDataContext())
{
var result = (from u in db.Students
where u.ID == id
select u.StudentName).FirstOrDefault();
if(result != null)
model.StudentName= result;
}
return View(model);
}
POST - This is where i want to save the new username for the student
[HttpPost]
public ActionResult _StudentNamePartial(StudentNameModel model)
{
if (ModelState.IsValid)
{
using (var db = new StudentDataContext())
{
try
{
}
catch (Exception)
{
throw;
}
}
return RedirectToAction("ProfileAccount");
}
return View(model);
}
Also i am having trouble that when i am displaying the username it is not hitting my Action method and it always reports that the Object reference is null. Any help will be great. Thanks :D
It would seem that you're trying to render a partial view from a controller action as part of the larger view. In this case, the partial view should be rendered within the ProfileAccount view.
You can structure the controller and views like this (rough outline):
ProfileAccount View Model:
public class ProfileAccountView
{
public StudentNameModel StudentName { get; set; }
}
Profile Controller:
[HttpGet]
public ActionResult ProfileAccount(int id)
{
// Get whatever info you need and store in a ViewModel
var model = new ProfileAccountView();
// Get the student info and store within ProfileAccountView
// Do your database reads
model.StudentName = new StudentNameModel { StudentName = result };
return View(model);
}
[HttpPost]
public ActionResult ProfileAccount(ProfileAccountView profile)
{
// Do whatever processing here
}
ProfileAccount View
#model School.Models.ProfileAccountView
#using (Html.BeginForm("ProfileAccount", "Profile"))
{
#Html.RenderPartial('_StudentNamePartial', Model.StudentName);
<button type="button" value="save" />
}
_StudentNamePartial Partial View
#model School.Models.StudentNameModel
<fieldset>
<ol>
<li>
#Html.LabelFor(m => m.StudentName)
#Html.TextBoxFor(m=>m.StudentName)
</li>
</ol>
</fieldset>
This is my first post so please go easy on me fellas. I am trying to implement a create form that utilizes jquery autocomplete. The create form allows users to enter data that will be saved to my database, via a submit button. Here is my code:
Controller
// GET: /Inspection1/Create
public ActionResult Create()
{
InspectionInfo model = new InspectionInfo
{
Submitted = DateTime.Now,
Contact = new Contact()
};
ViewBag.CountyName = new SelectList(db.Counties, "CountyName", "CountyName");
return View(model);
}
//
// POST: /Inspection1/Create
[HttpPost]
public ActionResult Create(InspectionInfo inspectioninfo)
{
if (ModelState.IsValid)
{
db.InspectionInfos.Add(inspectioninfo);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(inspectioninfo);
}
// this allows for autocompletion behavior
public ActionResult QuickSearchContact(string term)
{
var contacts = db.Contacts
.Where(r => r.ContactName.Contains(term))
.Take(10)
.Select(r => new { label = r.ContactName });
return Json(contacts, JsonRequestBehavior.AllowGet);
}
Models
public class InspectionInfo
{
[Key]
public int InspectionId { get; set; }
[DataType(DataType.Date)]
public virtual DateTime Submitted { get; set; }
[DataType(DataType.MultilineText)]
[MaxLength(1000)]
public string Comments { get; set; }
[Required]
public Contact Contact { get; set; }
public class Contact
{
[Key]
public string ContactName { get; set; }
View:
<div class="editor-label">
#Html.LabelFor(model => model.Contact)
</div>
<div class="editor-field">
<input type ="text" name ="q" data-autocomplete=
"#Url.Action("QuickSearchContact", "Inspection")"/>
#Html.ValidationMessageFor(model => model.Contact.ContactName)
</div>
JS
$(document).ready(function () {
$(":input[data-autocomplete]").each(function () {
$(this).autocomplete({ source: $(this).attr("data-autocomplete")});
});
The autocomplete function seems to be working fine. It will pull column data from the database as I require. However, any data entered in the autocomplete text box, appears NULL in the database after the user has saved the form. Help here would be greatly appreciated.
For model binding to work, generally input names must match property names of your model. Surprisingly, you have named your input "q"
<input type ="text" name ="q" data-autocomplete="..."/>
Just rename it according to your model
<input type ="text" name="Contact.ContactName" data-autocomplete="..."/>
You don't have your on the code above but, instead of using
<input type ="text" name ="q" data-autocomplete= "#Url.Action("QuickSearchContact", "Inspection")"/>
use:
#EditorFor(x = x.NameOfTextBox)
then either have an input button wrapped in a using tag
#using (Html.BeginForm("Create", "NameOfController", FormMethod.Post){
//all your model stuff goes here
}
or use and actionlink instead of :
#Html.ActionLink("Submit", "Create", "NameOfController", Model)
The provided information doesn't tell, but is is likely that the autocomplete part is not written within the form elements of the view:
#using (Html.BeginForm())
{
<p>
...
</p>
}
In MVC the form is defined within the brackets { .... } like above.