Submit form on change of dropdown - asp.net-mvc-3

I'm using MVC 3 and razor and have a form in which there is a dropdown. How do I submit the form when the value in the dropdown changes? I have no submit button.
#using (Html.BeginForm())
{
...
<div class="row">
<label>
Type of Card</label>
<div class="item">
#Html.DropDownList("PaymentFormModel.CardType", cardTypes, new { required = "required" })
</div>
</div>
...
}

Try like this
#Html.DropDownList("PaymentFormModel.CardType", cardTypes, new { required = "required", #onchange="submitform();" })
Here is the script for it:
function submitform()
{
$('form').submit();
}
hope it helps

Related

Validation error message not displayed in Asp.Net Core 2 MVC partial view

I have an index page with a list of "workbooks" titles and for each workbook, there is a "share" button. When pressing the button a bootstrap model (i.e. dialog) appears which displays the title of the workbook and a textarea allowing the user to type in a sharees email addresses.
When the user presses on the "share" button, I am calling a javascript function which calls a controller action that returns a partial view containing the modal dialog with a form inside it. The problem is that after pressing the submit button (i.e. "Share") there are no validation errors being shown to the user and I am not sure why that is. Could anyone provide some ideas, please?
That is my main (index.cshtml) page:
#model DNAAnalysisCore.Models.WorkBookModel
#{
}
#section BodyFill
{
<script type="text/javascript">
function showSharingView(title) {
var url = "#Url.Action("ShowShareDialog", "Home")" + "?workbookTitle=" + encodeURI(title);
$('#shareFormContainer').load(url,
function() {
$('#shareFormModal').modal("show");
});
}
function hideSharingView() {
$('#shareFormModal').modal("hide");
}
</script>
<div id="shareFormContainer" >
<!--PLACEHOLDER FOR SHARE DIALOG -->
</div>
<div class="workbook-container">
<table class="table">
<tbody>
#foreach (var workbook in Model.Workbooks)
{
<tr>
<td>#Html.ActionLink(workbook.Name, "Open", "OpenAnalytics", new {id = Model.Id, workbook = workbook.Name})</td>
<td>
<button title="Share" class="share-button" onclick='showSharingView("#workbook.Name")'> </button>
</td>
</tr>
}
</tbody>
</table>
</div>
}
That is my Controller:
public class HomeController : Controller
{
[HttpGet]
public IActionResult ShowShareDialog(string workbookTitle)
{
var shareModel = new ShareModel
{
Title = workbookTitle
};
return PartialView("_ShareView", shareModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult ShareWorkbook(string emails, string title)
{
var share = new ShareModel
{
Emails = emails
};
// TODO EMAIL THE SHARED WORKBOOK using the 'title' of the workbook and the 'email' string value
// return no content to avoid page refresh
return NoContent();
}
}
This is my partial view/modal dialog (_ShareView):
#using DNAAnalysisCore.Resources
#model DNAAnalysisCore.Models.ShareModel
<!-- Modal -->
<div class="modal fade" id="shareFormModal" role="dialog">
<div class="modal-dialog modal-md">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Share Workbook - #Model.Title</h4>
</div>
#using (Html.BeginForm("ShareWorkbook", "Home", FormMethod.Post))
{
<div class="modal-body">
<label>#BaseLanguage.Share_workbook_Instruction_text</label>
<div class="form-group">
<textarea class="form-control" asp-for="Emails" rows="4" cols="50" placeholder="#BaseLanguage.ShareDialogPlaceholder"></textarea>
#* TODO add client-side validation using jquery.validate.unobtrusive.js. See US268276 *#
<span asp-validation-for="Emails" class="text-danger"></span>
</div>
<input asp-for="Title" />
</div>
<div class="modal-footer">
<button type="submit" onclick="hideSharingView()" class="btn btn-primary">Share</button>
<button id="btnCancelDialog" type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
</div>
}
</div>
</div>
</div>
#section Scripts {
#{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}
This is my ShareModel:
public class ShareModel
{
[HiddenInput]
public string Title { get; set; }
[Required]
public string Emails { get; set; }
}
The form is not added to the page when the page loads, the unobtrusive validation will not pick it up.A simple solution is to use $.validator.unobtrusive.parse("#id-of-the-form");.Refer to here.
1.Add id to your form in _ShareView partial view:
#using (Html.BeginForm("ShareWorkbook", "Home", FormMethod.Post,new { #id="partialform"}))
2.Introduce validation file _ValidationScriptsPartial.cshtml into main page(Index.cshtml) and manually register the form with the unobtrusive validation.
#section Scripts
{
#await Html.PartialAsync("_ValidationScriptsPartial")
<script type="text/javascript">
function showSharingView(title) {
var url = "#Url.Action("ShowShareDialog", "Home")" + "?workbookTitle=" + encodeURI(title);
$('#shareFormContainer').load(url,
function() {
$('#shareFormModal').modal("show");
$.validator.unobtrusive.parse("#partialform");
});
}
function hideSharingView() {
$('#shareFormModal').modal("hide");
}
</script>
}

Saving multiple partial views from one main page

Here is my requirement :
I am designing a page to add a vehicle to the database :
Normal vehicle information [Model - Inventory]
Some other features [Model - IList]
Here is my index.cshtml page
#model Model.ViewModel.VehicleViewModel
<div>
<div class='col-md-12'>
<div class="form-group">
<input id="mainFormSubmit" type="button" value="Save" class="btn btn-default" />
</div>
</div>
#{Html.RenderPartial("~/Views/Shared/_InventoryPartial.cshtml", Model.InventoryVM);}
#{Html.RenderPartial("~/Views/Shared/_StandardFeaturePartial.cshtml", Model.StandardFeatures);}
</div>
<script type="text/javascript">
$('#mainFormSubmit').click(function () {
$('#InventoryForm').submit();
$("#StandardFeatureForm").submit();
});
</script>
This is my view model class
public class VehicleViewModel
{
public InventoryViewModel InventoryVM { get; set; }
public IList<StandardFeature> StandardFeatures { get; set; }
}
The Inventory partial view [_InventoryPartial.cshtml]
#model Model.ViewModel.InventoryViewModel
#{
var options = new AjaxOptions() { HttpMethod = "Post" };
}
<div class="container">
<div class="row">
<div class="col-md-12">
#using (Ajax.BeginForm("InventorySave", "AddVehicle", options, new { id = "InventoryForm" }))
{
<fieldset>
<legend>Inventory Info</legend>
<div class='col-md-6'>
<!-- VIN input-->
<div class="form-group">
#Html.LabelFor(x => x.VIN, new { #class = "col-md-4 control-label" })
<div class="col-md-7">
#Html.TextBoxFor(x => x.VIN, new { #class = "form-control", #placeholder = "VIN" })
</div>
</div>
</div>
</fieldset>
}
The standard feature partial view [_StandardFeaturePartial.cshtml]
==
#model IEnumerable<Model.DomainModel.StandardFeature>
#{
var options = new AjaxOptions() { HttpMethod = "Post" };
}
<div class="container">
<div class="row">
<div class="col-md-12">
#using (Ajax.BeginForm("StandardFeatureSave", "AddVehicle", options, new { id = "StandardFeatureForm" }))
{
When I am clicking on index page SAVE button, only
$('#InventoryForm').submit();
$("#StandardFeatureForm").submit();
last one(StandardFeatureForm) is executing.
Please let me know if this process is correct, and what could be the reason of this issue.
You should not call the submit method twice. Depending of the browser you can face different issues :
the form submission causes the browser to navigate to the form action and the submission
of the first may prevent the submission of the second
The browser could detected there are two requests and discards the
first submit.
In your case it will be easier to wrap your two partial views inside a unique form.
#using (Ajax.BeginForm("InventorySave", "AddVehicle", FormMethod.Post, new { id = "InventoryForm" }))
{
#{Html.RenderPartial("~/Views/Shared/_InventoryPartial.cshtml", Model.InventoryVM);}
#{Html.RenderPartial("~/Views/Shared/_StandardFeaturePartial.cshtml", Model.StandardFeatures);}
}
However when the partial views render they are not generating the correct name attributes for the larger modelModel.ViewModel.VehicleViewModel you want to use :
public void InventorySave(VehicleViewModel vehicleViewModel) {}
In this case you should use EditorTempmlate instead of partial views. It's simple to do from your partial views and this post should help you :Post a form with multiple partial views
Basically, drag your partials to the folder ~/Shared/EditorTemplates/
and rename them to match the model name they are the editor templates
for.
Finally something like :
#model Model.ViewModel.VehicleViewModel
#using (Html.BeginForm("InventorySave", "AddVehicle", FormMethod.Post, new { id = "InventoryForm" }))
{
#Html.EditorFor(m => m.InventoryVM);
#Html.EditorFor(m => m.StandardFeatures});
}
The Ajax.BeginForm helper already has a submit event associated to it which creates an Ajax POST request. When you are manually submitting your form using $('#InventoryForm').submit();, you're calling both and the submit events which can have strange side effects.
There are a few ways around this. Here is one solution
Change your forms to a regular HTML form using the Html.BeingForm helper.
Amend your script to create ajax requests and use the form data
$('#InventoryForm').submit(function(e) {
e.preventDefault();
$.post($(this).attr("action"), $(this).serialize(), function(r) {
//Do something
});
});
$('#StandardFeatureForm').submit(function(e) {
e.preventDefault();
$.post($(this).attr("action"), $(this).serialize(), function(r) {
//Do something
});
});
Hope this helps

MVC3 boolean editor template with multiple controls for the same property

I'm using c#, MVC3, Razor and Zurb Foundation 4.
I have a custom editor template for boolean values that will show different UI for different input devices. (visibility is controlled by Foundation's hide-for / show-for css classes)
The problem is that because all of these UI elements are always on the page, only the values in the first one will get bound to the model on post back.
So I either need to find a way of actually removing the HTML for the hidden divs or find a way to use a true value from any of the three elements (they all default to false so whichever is set to true would be the visible one)
This is my Boolean.cshtml:
#model bool
#using System.Web.UI.WebControls
#using Helpers
<div class="hide-for-small">
<div class="hide-for-touch">
<div class="editor-field">
#Html.CheckBoxFor(model => model)
</div>
</div>
</div>
<div class="show-for-small">
<div class="hide-for-touch">
<div class="editor-field">
#{
List<BoolString> ynb = new List<BoolString>();
ynb.Add(new BoolString(false, "No"));
ynb.Add(new BoolString(true, "Yes"));
}
#Html.DropDownListFor(model => model, new SelectList(ynb, "Value", "Description"))
</div>
</div>
</div>
<div class="show-for-touch">
<div class="switch round">
<input id='#ViewData.TemplateInfo.HtmlFieldPrefix + ".Off"' name='#ViewData.TemplateInfo.HtmlFieldPrefix' type='radio' checked />
<label for='#ViewData.TemplateInfo.HtmlFieldPrefix + ".Off"' onclick=''>Off</label>
<input id='#ViewData.TemplateInfo.HtmlFieldPrefix + ".On"' name='#ViewData.TemplateInfo.HtmlFieldPrefix' type='radio' />
<label for='#ViewData.TemplateInfo.HtmlFieldPrefix + ".On"' onclick=''>On</label>
</div>
</div>
Currently the checkbox works fine but the dropdown does not. (I always get false for my model property by the time I get back to the controller).
If I move the dropdown div before the checkbox then the dropdown works but the checkbox does not.
Note that I'm not sure about the touch element yet so it may be wrong anyway. I'm not bothered about getting that working until I have this problem sorted out.
I cooked up a brute force apporach syncronizing each of the inputs using javascript & jquery. Please post if you find a better way
TEST FORM
#using BooleanEditorTemplate.Controllers
#model bool
#{ var modelname = "mmm"; }
#using(Html.BeginForm("Index","Home")){
<div class="hide-for-small">
<div class="hide-for-touch">
<div class="editor-field">
#Html.CheckBox(modelname, Model)
</div>
</div>
</div>
<div class="show-for-small">
<div class="hide-for-touch">
<div class="editor-field">
#{
List<BoolString> ynb = new List<BoolString>();
ynb.Add(new BoolString(false, "No"));
ynb.Add(new BoolString(true, "Yes"));
}
#Html.DropDownList(modelname, new SelectList(ynb, "Value", "Description"))
</div>
</div>
</div>
<div class="show-for-touch">
<div class="switch round">
<input id='#modelname' name='#modelname' type='radio' checked value="on"/>
<label for='#modelname' onclick=''>Off</label>
<input id='#modelname' name='#modelname' type='radio' value="off"/>
<label for='#modelname' onclick=''>On</label>
</div>
</div>
<input type="submit" value="OK"/>
}
TEST SCRIPT
<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<script>
$(function () {
$('[name="#modelname"]').change(
function () {
var id = $(this).attr("id");
var name = $(this).attr("name");
var checked = false;
switch (this.type)
{
case 'checkbox':
checked = $(this).is(":checked");
break;
case 'select-one':
checked = $(this).val().toUpperCase() == 'TRUE';
break;
case 'radio':
checked = $('input[type="radio"][name=' + name + ']:checked').val().toUpperCase() === 'ON';
break;
}
//checkbox
$('input[type="checkbox"][name="' + name + '"]').prop('checked', checked);
//select the select-one
if (checked)
$('select[name="' + name + '"]').val('True');
else
$('select[name="' + name + '"]').val('False');
//select the proper radio
if (checked)
$('input[type="radio"][name='+ name +'][value="on"]').prop("checked", true);
else
$('input[type="radio"][name=' + name + '][value="off"]').prop("checked", true);
});
});
</script>
and my test controler/classes setup
public class HomeController : Controller
{
public ActionResult Index()
{
return View("Index",true);
}
[HttpPost]
public ActionResult Index(Boolean mmm)
{
return null;
}
}
public class BoolString
{
public bool Value { get; set; }
public string Description { get; set; }
public BoolString(bool val, string desc)
{
this.Value = val;
this.Description = desc;
}
}
So this works on my box. I did have to make several modifications as I didn't test this within the editor framework. Undoutably, you'd have to make several more to adapt it back within the scope of your framework.

pass a value of the form from view to controller

how do i pass the value of the form, which is (i assume) a string of date to the controller...
here is my view:
<script type="text/javascript" language="javascript">
$(function () {
$(".datepicker").datepicker({ onSelect: function (dateText, inst) { $("FORM").submit(); },
altField: ".alternate"
});
});
</script>
#model IEnumerable<CorReservation.Models.Reservation>
#{
ViewBag.Title = "Index";
}
<div class="divRightSide">
<div>
<div class="datepicker">
</div>
<form action="/" title="fff">
<input type="text" class="alternate" readonly="readonly" />
</form>
</div>
// do something eg. foreach (var item in Model)
{ #Html.DisplayFor(modelItem => item.Date)}
here is my controller: i want to pass the date selected from the datepicker to the controller and then the controller would return an Ienumerable of reservations...
DateTime date = System.DateTime.Now;
private ReservationEntities db = new ReservationEntities();
public ViewResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string dateInput)
{
date = Convert.ToDateTime(dateInput);
var reservations = db.Reservations.Where(r=> r.Date ==date).Include(r => r.Employee).Include(r => r.Room).OrderByDescending(r => r.Date);
return View(reservations);
}
There are 2 ways to do this. Make the form input name attribute match the expected attribute in your controller.
For example:
<input type="text" class="alternate" readonly="readonly" name="dateInput" />
Or if there's going to be a lot of input values, use a Model.
It's automatically done based on the 'name' attribute of the HTML fields you want to submit.
Change your form to
<form action="/" title="fff">
<input name="dateInput" type="text" class="alternate" readonly="readonly" />
</form>
And it should work just like that.
Also, as you are using Razor syntax, you could use the Razor HTML helpers like so
#model IEnumerable<CorReservation.Models.Reservation>
#{
ViewBag.Title = "Index";
}
<div class="divRightSide">
<div>
<div class="datepicker">
</div>
#using(#Html.BeginForm("<your controller name>", "<your action name e.g. Index>"){
Html.TextBox("dateInput", "", new { #readonly="readonly", #class="alternate" })
}
</div>
// do something eg. foreach (var item in Model)
{ #Html.DisplayFor(modelItem => item.Date)}

How i can submit multiple objects inside the form post values to be added

i have a create view to add answers to a question, currently the user can only add one answer at the same time when he clicks on the submit button, instead of this i want the user to be able to insert multiple answers objects into the same view and then the system to add all these new answer objects to the database after the user click on the submit button, my current view looks as the follow:-
#model Elearning.Models.Answer
#{
ViewBag.Title = "Create";
}
<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>
<div id = "remove">
#using (Ajax.BeginForm("Create", "Answer", new AjaxOptions
{
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "remove"
}))
{
<div id = "returnedquestion">
#Html.ValidationSummary(true)
<fieldset>
<legend>Answer</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
</fieldset>
<input type= "hidden" name = "questionid" value = #ViewBag.questionid>
<input type= "hidden" name = "assessmentid" value = #ViewBag.assessmentid>
<input type="submit" value="Add answer" />
</div>
}
</div>
and the action methods look as the follow:-
public ActionResult Create(int questionid)//, int assessmentid)
{
ViewBag.questionid = questionid;
Answer answer = new Answer();
return PartialView("_answer",answer);
}
//
// POST: /Answer/Create
[HttpPost]
public ActionResult Create(int questionid, Answer a)
{
if (ModelState.IsValid)
{
repository.AddAnswer(a);
repository.Save();
return PartialView("_details",a);
}
return View(a);}
so how i can modify the above code to be able to insert multiple answer objects at the same view and then submit these answers objects at the same time when the user click on the submit button?
Try Post a List
Add input by javascript when user click "Add Answer".
And when submit the form ,it will post all answer data to binding to List
<script>
$(document).ready(function () {
var anwserCount = 1;
$("#addbutton").click(function () {
$("#AnwsersDiv")
.append("<input type='text' name='Anwsers[" + anwserCount + "]'/>");
anwserCount += 1;
});
});
</script>
#using (Html.BeginForm())
{
<div id="AnwsersDiv">
<input type="text" name="Anwsers[0]" />
</div>
<input id="addbutton" type="button" value="Add answer" />
<input type="submit" value="submit" />
}
Model
public class Answer
{
public List<String> Anwsers { get; set; }
}
When submit the form
I think this is what you are looking for
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Conclusion: you should make the post action with ICollection<Answer> Parameter, then it will be easy to get them when you post your main form, and create the appropriate QUESTION object, then save them all with only one submit.

Resources