This is how my view looks like currently.
#model DatePicker.Models.ViewModels.Appointment.CreateAppointmentSelectPersons
#{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
<link href="~/Content/themes/base/minified/jquery-ui.min.css" rel="stylesheet"/>
}
#*Main Form*#
#using(Ajax.BeginForm("Create","Appointment", new AjaxOptions{HttpMethod = "POST"}))
{
#Html.AntiForgeryToken()
<h4>Step 2</h4>
<hr />
#Html.ValidationSummary()
#Html.HiddenFor(m=>m.AppointmentId)
#*Child Form1*#
using (Ajax.BeginForm("AddAttendeeManual", "Attendee", new AjaxOptions { HttpMethod = "POST", OnSuccess = "doneSuperOffice" }))
{
#Html.HiddenFor(m=>m.SelectedManualEmail.AppointmentId)
<div class="form-group">
#Html.LabelFor(m => m.SelectedManualEmail.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-8 input-group">
#Html.TextBoxFor(m => m.SelectedManualEmail.Email, new { id = "Email", #class = "form-control",PlaceHolder="Email"})
<input type='submit' id="btnEmail" class="btn btn-default" value="Add>>" />
</div>
</div>
}
if (Model.IsSuperOfficeConnected)
{
#*Child Form 2*#
using (Ajax.BeginForm("AddAttendeeSuperOffice","Attendee",new AjaxOptions{HttpMethod = "POST", OnSuccess = "doneManualEmail"}))
{
#Html.HiddenFor(m => m.SelectedSuperOfficeEmail.FirstName, new { id = "SelectedSuperOfficeEmail_FirstName" })
#Html.HiddenFor(m => m.SelectedSuperOfficeEmail.LastName, new { id = "SelectedSuperOfficeEmail_LastName" })
#Html.HiddenFor(m=>m.SelectedSuperOfficeEmail.AppointmentId)
#Html.HiddenFor(m => m.SelectedSuperOfficeEmail.SuperOfficePersonId, new { id = "SelectedSuperOfficeEmail_SuperOfficePersonId" })
<div class="form-group">
#Html.LabelFor(m => m.SelectedSuperOfficeEmail.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-8 input-group">
#Html.TextBoxFor(m => m.SelectedSuperOfficeEmail.Email, new { id = "SelectedSuperOfficeEmail", #class = "form-control", PlaceHolder = "Search in SuperOffice" })
<input type='submit' id="btnSuperOffice" class="btn btn-default" value="Add>>" />
</div>
</div>
}
}
if (Model.IsInternalAddressBookEmpty)
{
#*Child Form3*#
using (Ajax.BeginForm("AddAttendeeInternalAddressBook", "Attendee", new AjaxOptions { HttpMethod = "POST", OnSuccess = "doneInternalAddressbook" }))
{
#Html.HiddenFor(m=>m.SelectedAddressBookPerson.FirstName)
#Html.HiddenFor(m=>m.SelectedAddressBookPerson.LastName)
#Html.HiddenFor(m=>m.SelectedAddressBookPerson.AppointmentId)
<div class="form-group">
#Html.LabelFor(m => m.SelectedAddressBookPerson.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-8 input-group">
#Html.TextBoxFor(m => m.SelectedAddressBookPerson.Email, new { id = "SelectedAddressBookPerson", #class = "form-control", PlaceHolder = "Search in AddressBook..." })
<input type='submit' id="btnAddressBook" class="btn btn-default" value="Add>>">
</div>
</div>
}
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input class="btn btn-default" value="<<Previous"/>
<input type="submit" class="btn btn-default" value="Next>>" />
</div>
</div>
}
<style>
.ui-autocomplete-loading {
background: url('/Content/themes/base/images/ui-anim_basic_16x16.gif') no-repeat right center;
}
</style>
#section Scripts{
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/Scripts/jquery-ui-1.10.4.min.js")
#Scripts.Render("~/Scripts/jquery.unobtrusive-ajax.min.js")
<script type="text/javascript">
$(function () {
$("#SelectedSuperOfficeEmail").
autocomplete({
source: '/Appointment/SuperOfficePerson',
minLength: 1,
select: function (event, ui) {
$('#SelectedSuperOfficeEmail').val(ui.item.value);
$(#Html.IdFor(m => m.SelectedSuperOfficeEmail.FirstName)).val(ui.item.FirstName);
$(#Html.IdFor(m => m.SelectedSuperOfficeEmail.LastName)).val(ui.item.LastName);
$(#Html.IdFor(m => m.SelectedSuperOfficeEmail.SuperOfficePersonId)).val(ui.item.ExternalPersonId);
}
});
$("#SelectedAddressBookPerson").autocomplete({
source: '/Appointment/AddressBookPerson',
minLength: 1,
select: function(event,ui) {
$(#Html.IdFor((m=>m.SelectedAddressBookPerson.FirstName))).val(ui.item.FirstName);
$(#Html.IdFor(m=>m.SelectedAddressBookPerson.LastName)).val(ui.item.LastName);
},
});
});
function doneManualEmail() {
$("#Email").val('');
}
function doneSuperOffice() {
$("#SelectedSuperOfficeEmail").val('');
}
function doneInternalAddressBook() {
$("#SelectedAddressBookPerson").val('');
}
</script>
}
And the controller:
[HttpPost]
public void AddAttendeeSuperOffice(CreateAppointmentSelectPersons superOfficePerson)
{
_attendeeRepository.AddSuperOfficeAttende(superOfficePerson.SelectedSuperOfficeEmail.AppointmentId,
superOfficePerson.SelectedSuperOfficeEmail.FirstName,
superOfficePerson.SelectedSuperOfficeEmail.LastName,
superOfficePerson.SelectedSuperOfficeEmail.Email,
superOfficePerson.SelectedSuperOfficeEmail.SuperOfficePersonId);
}
[HttpPost]
public void AddAttendeeInternalAddressBook(CreateAppointmentSelectPersons internalAddressbookPerson)
{
_attendeeRepository.AddInternalAddressBookAttendee(
internalAddressbookPerson.SelectedAddressBookPerson.AppointmentId,
internalAddressbookPerson.SelectedAddressBookPerson.FirstName,
internalAddressbookPerson.SelectedAddressBookPerson.LastName,
internalAddressbookPerson.SelectedAddressBookPerson.Email);
}
[HttpPost]
public void AddAttendeeManual(CreateAppointmentSelectPersons manualEmail)
{
_attendeeRepository.AddManualAttendee(manualEmail.SelectedManualEmail.AppointmentId,
manualEmail.SelectedManualEmail.Email);
}
Here, Child Form2works perfectly, it calls my controller when button is clicked and OnSuccess textbox gets empty, exactly as I wanted.
Problem1: For the Child Form3 it calls the controller but OnSuccess, doesn't make the textbox empty.
Problem2: For the Child Form1 it doesn't call my controller at all, nothing happens when i click the button
For starters, you may want to either create a done() function for each of those forms, or pass it which form has completed (unless every form, after it's been executed, does the same thing). e.g.
#* Child Form 1 *#
new AjaxOptions { ... OnSuccess = "form1Done()" ... }
#* Child Form 2 *#
new AjaxOptions { ... OnSuccess = "form2Done()" ... }
#* Child Form 3 *#
new AjaxOptions { ... OnSuccess = "form3Done()" ... }
~OR~
#* Child Form 1 *#
new AjaxOptions { ... OnSuccess = "done(1)" ... }
#* Child Form 2 *#
new AjaxOptions { ... OnSuccess = "done(2)" ... }
#* Child Form 3 *#
new AjaxOptions { ... OnSuccess = "done(3)" ... }
Secondly, There are more options than OnSuccess for the AjaxOptions method. It may make sense (at least while debugging) to add methods to OnFailure or OnSuccess so you can get more insight as to what's happening. Also, make use of the debugger within your browser and see if the calls are being executed.
For now, there's not enough information to solve your issue, but hopefully you'll either end up solving it by using the above, or get more information to update the question with.
If you do end up updating the question, please leave a comment on this answer and I'll do my best to help.
Related
I am making a page where I'd like to be able to have several different actions happening depending on what is being done.
for instance I have a dropdown where I want different forms to be loaded in to the page depending on the selection in the dropdown.
Currently I'm doing it like this:
$(document).ready(function () {
$('#subject').on("change", function (e) {
e.preventDefault();
var selectedVal = $('#subject').val();
$.ajax({
url: "ContactUs/GetForm",
type: "POST",
data: { searchValue: selectedVal },
async: true,
success: function (data) {
$('#renderForms').empty();
$('#renderForms').append(data);
},
error: function (xhr, ajaxOptions, thrownError) {
alert("An error has occured!!! " + xhr.status + " && " + xhr.responseText);
}
});
}; etc...
this hits the following method no problem
[HttpPost]
public ActionResult GetForm(string searchValue)
{
//my code here
return PartialView("_Bills",contactModel.contactBillsModel);
}
However when I click on it also hit the following method which is not my intention.
[HttpPost]
public ActionResult Index(Contact_Portal.Models.ContactViewModel contactModel)
{
return View(contactModel);
}
How do I prevent this behaviour ?
the last HttpPost I'm using in a button in the partial page like this
<input id="Send" type="submit" value="Send" class="btn btn-default" />
Edit:
Adding Additional Information per requested.
the view with the dropdown
#model WebPortal.Models.FormViewModel
#{
ViewBag.Title = "multiple forms";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>multiple forms</h2>
<label>My selection is... </label>
#Html.DropDownListFor(model => model.contactSelectListItems, new List<SelectListItem>
{
new SelectListItem() {Text = "option 1", Value="option 1"},
new SelectListItem() {Text = "option 2", Value="option 2"},
new SelectListItem() {Text = "option 3", Value="option 3"},
new SelectListItem() {Text = "option 4", Value="option 4"}
}, "--choose--", new { id = "subject", #class="dropdown-item"})
<div id="renderForms">
</div>
one of the views with the forms:
#model WebPortal.Models.AformViewModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>A Form</h4>
<hr />
<div id="InfoBox" class="form-group col-md-20">
Remember to fill out this text with relevant text.
</div>
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="container">
<div class="row">
<div class="form-group form-group-sm col-sm-6">
<div class="row">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-sm-9">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group form-group-sm col-sm-6">
<div class="row">
#Html.LabelFor(model => model.Phone, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-sm-9">
#Html.EditorFor(model => model.Phone, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Phone, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group form-group-sm col-sm-6">
<div class="row">
<div class="col-sm-9">
<!--#Html.Action("Index", "ContactUs")-->
<input id="Send" type="submit" value="Send" class="btn btn-default" />
</div>
</div>
</div>
</div>
</div>
</div>
Well I have a solution thou I'm not really happy with it but it works.
this is what I've done since posting my question:
I've changed on request from Stephen Muecke this part here:
<div class="form-group form-group-sm col-sm-6">
<div class="row">
<div class="col-sm-9">
<!--#Html.Action("Index", "ContactUs")-->
<input id="Send" type="submit" value="Send" class="btn btn-default" />
</div>
</div>
</div>
to
<div class="form-group form-group-sm col-sm-6">
<div class="row">
<div class="col-sm-9">
<input id="Send" type="submit" value="Send" class="btn btn-default" />
</div>
</div>
</div>
and after that It removed my problem with activating both my HttpPost Actions GetForm and Index(viewmodel)
but I got the new problem of the submit button activating the GetForm action instead of the Index(viewmodel) action.
So because of this I changed my submit button to the following
<input id="Send" type="submit" value="Send" formaction=#Url.Action("Index","ContactUs") class="btn btn-default" />
this change solved my problem for now but I feel that the input submit button now is now not inline with the ideas behind unobtrusive event handling.
Edit:
instead of the above submit button line I added this to the html form:
#using (Html.BeginForm("Index", "ContactUs"))
The problem is that your input with type="submit" is submitting the form. This is the standard behaviour for HTML-forms.
Change the input's type to type="button":
<input id="Send" type="button" value="Send" class="btn btn-default" />
Then change the event in jQuery to "click":
$(document).ready(function () {
$('#subject').on("click", function (e) {
e.preventDefault();
var selectedVal = $('#subject').val();
$.ajax({
url: "ContactUs/GetForm",
type: "POST",
data: { searchValue: selectedVal },
async: true,
success: function (data) {
$('#renderForms').empty();
$('#renderForms').append(data);
},
error: function (xhr, ajaxOptions, thrownError) {
alert("An error has occured!!! " + xhr.status + " && " + xhr.responseText);
}
});
}; etc...
How can I call an MVC action method with complex parameters, like the below, from a button click event?
[ValidateInput(false)]
[HttpPost]
public ActionResult Export(ViewModel vm)
{
// some logic
}
I have made it a POST action because I need to pass HTML tags of the current page on which the button is to the action method which is too long. I have tried this but this its for a GET operation
<input type="button" value="Detail" onclick="location.href='#Url.Action("Export", "Report")?html=' + $('#test').html()" />
If you want to do this using a button click you can subscribe the to click event of the button in JS. In your JS, you can do an ajax post, which will post a JSON object (your VM) to your action:
Razor:
<input type="button" value="Detail" id="buttonId" />
JS:
$('#buttonId').click(function () { //On click of your button
var property1 = $('#property1Id').val(); //Get the values from the page you want to post
var property2 = $('#property2Id').val();
var JSONObject = { // Create JSON object to pass through AJAX
Property1: property1, //Make sure these names match the properties in VM
Property2: property2
};
$.ajax({ //Do an ajax post to the controller
type: 'POST',
url: './Controller/Action',
data: JSON.stringify(JSONObject),
contentType: "application/json; charset=utf-8",
dataType: "json"
});
Another way to do this is submit the view model using a form.
#using (Html.BeginForm("ActionName", "ControllerName", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.PropertyName1, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="text" id="PropertyName1" name="PropertyName1" class="form-control" />
#Html.ValidationMessageFor(model => model.PropertyName1, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PropertyName2, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PropertyName2, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PropertyName2, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Button text" class="btn btn-primary" />
</div>
</div>
</div>
}
You can do that with HTML form
<form action="#Url.Action("Export", "Report")" method="POST">
<input type="hidden" name="html" value="ADD YOUR HTML HERE">
<input type="button" value="Detail" />
</form>
And inside your controller you need to use html parameter
[ValidateInput(false)]
[HttpPost]
public ActionResult Export(ViewModel vm, string html)
{
// some logic
}
try this
<form action="#Url.Action("Export", "Report")" method="POST">
<input type="hidden" name="html" id="html" value="ADD YOUR HTML HERE">
<input type="button" id="btn1" value="Detail" />
</form>
add Script in js
$("#btn1").click(function(){
$("#html").val($('#test').html());
})
add param in your method string html
#Html.ActionLink("edit", "Edit", "MedQuantityType", new { id = item.Med_quan_typeId }, new
{
#* Needed to link to the html of the modal*#
data_target = "#mymodel",
#* Tells the bootstrap javascript to do its thing*#
data_toggle = "modal",
})
This the action link I try to popup partial view in bootstrap model, it's working fine when I try to edit & save it works except model state is not valid
here my controller code
public async Task<ActionResult > Edit([Bind(Include = "Med_quan_typeId,Med_quan_type,Med_quantity")] Med_quantity_type med_quantity_type)
{
if (ModelState.IsValid)
{
db.Entry(med_quantity_type).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
return PartialView(med_quantity_type);
}
If my model state fails the controller return partial view but its not popup in mymodel this is my partial view cshtml page
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Medicine Quantity Type - Edit</h4>
</div>
<div class="modal-body">
#using (Ajax.BeginForm("Edit", "MedQuantityType",
new AjaxOptions
{
HttpMethod = "GET",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "mymodel"
}))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Med_quan_typeId)
<div class="form-group">
<div class="col-md-3 col-md-offset-1">
#Html.LabelFor(model => model.Med_quan_type, new { #class = "control-label " })
</div>
<div class="col-md-6">
#Html.TextBoxFor(model => model.Med_quan_type, new { #class = "form-control", #id = "txtquantype" })
#Html.ValidationMessageFor(model => model.Med_quan_type)
</div>
</div>
<div class="form-group">
<div class="col-md-3 col-md-offset-1">
#Html.LabelFor(model => model.Med_quantity, new { #class = "control-label" })
</div>
<div class="col-md-6">
#Html.TextBoxFor(model => model.Med_quantity, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Med_quantity)
</div>
</div>
</div>
<div class="modal-footer">
<input type="submit" value="Save" class="btn btn-success" id="btnsubmit" />
<button type="button" class="btn btn-danger" data-dismiss="modal">Cancel</button>
</div>
<div ID ="popupform"class="popover">
<div class="alert-danger"> Please Fix The errors </div>
</div>
}
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function () {
$(function () {
debugger;
// when the modal is closed
$('#mymodel').on('hidden.bs.modal', function () {
// remove the bs.modal data attribute from it
$(this).removeData('bs.modal');
// and empty the modal-content element
$('#mymodel .modal-content').empty();
});
});
});
</script >
Please help anyone how to popup partial view, once controller return partial view
From Task<ActionResult > to Task<PartialViewResult> then change your ActionLink to RenderPartial.
It should work fine.
Change the return type of your action to Task<PartialView>
I have the following partial view
#model Marks.Web.ViewModels.AssignmentMarkViewModel
<div class="table">
#using (Ajax.BeginForm("_MarkInlineEditor", "Semesters", new AjaxOptions
{
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "editor" + Model.AssignmentId
}, new { #id = "editor" + Model.AssignmentId, #class = "tr" }))
{
<span class="td">#Model.AssignmentName</span>
<span class="td">#(Model.Mark.HasValue ? Model.Mark.Value.ToString("#.##") : "")</span>
<span class="td">#Model.Weight.ToString("#.##")</span>
<span class="td">#(Model.ActualMark.HasValue ? Model.ActualMark.Value.ToString("#.##") : "")</span>
#Html.HiddenFor(model => model.AssignmentId)
<span class="td"><button type="submit" name="option" value="edit">Edit</button></span>
<span class="td"><button type="submit" name="option" value="clear">Clear</button></span>
}
</div>
When clicking the Edit button, the action method returns this other partial view, which serves as the editing view:
#model Marks.Web.ViewModels.AssignmentMarkViewModel
<div class="table">
#using (Ajax.BeginForm("_MarkInlineViewer", "Semesters", new AjaxOptions
{
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "viewer" + Model.AssignmentId
}, new { #id = "viewer" + Model.AssignmentId, #class = "tr" }))
{
<span class="td">#Html.TextBoxFor(m => m.AssignmentName)</span>
<span class="td">#Html.TextBoxFor(m => m.Mark)</span>
<span class="td">#Html.TextBoxFor(m => m.Weight, new { required="required", type="number" })</span>
<span class="td">xx</span>
#Html.HiddenFor(model => model.AssignmentId)
<span class="td"><button type="submit" name="option" value="save">Save</button></span>
<span class="td"><button type="submit" name="option" value="cancel">Cancel</button></span>
}
</div>
When I click the Save button, the action method called should be _MarkInlineViewer but it instead calls _MarkInlineEditor. Is there something wrong with how I'm doing this? Here are the action methods:
public PartialViewResult _MarkInlineEditor(string option, int assignmentId)
{
var marksRepo = new MarksRepo();
var mark = marksRepo.GetMarkById(assignmentId);
var markVm = Mapper.Map<AssignmentMarkViewModel>(mark);
return PartialView(option == "edit" ? "_MarkInlineEditor" : "_MarkInlineViewer", markVm);
}
public PartialViewResult _MarkInlineViewer(AssignmentMarkViewModel amvm)
{
var marksRepo = new MarksRepo();
var mark = Mapper.Map<AssignmentMark>(amvm);
var updatedMark = marksRepo.UpdateMark(mark);
var updatedAmvm = Mapper.Map<AssignmentMarkViewModel>(updatedMark);
return PartialView("_MarkInlineViewer", updatedAmvm);
}
It turns out I can't replace the form I'm working with like I was trying to do here, so for my UpdateTargetId I used the parent div instead of the form's ID.
I am creating an application on MVC Mobile and having a problem. Here i have a Partial view load on a page run-time by ajax. In which i have a simple form which will submit with ajax request like bellow:
#model Test.Models.TestModel
#using (this.Ajax.BeginForm("Create", "Test", Model, new AjaxOptions { UpdateTargetId = "divResult", LoadingElementId = "loading", LoadingElementDuration = 2000, HttpMethod = "Post" }, new { id = "frmCreate" }))
{
#Html.AntiForgeryToken()
<div class="messageBox">#Html.Raw(TempData["Message"])</div>
<div class="atmForm">
<div class="control-group">
#Html.LabelFor(x => x.Name)
#Html.TextBoxFor(x => x.Name, new { #placeholder = "Name", #class = "inputStyle" }) #Html.ValidationMessageFor(x => x.Name)
</div>
<div class="control-group">
#Html.LabelFor(x => x.Notes)
#Html.TextAreaFor(x => x.Notes, new { #placeholder = "Notes", #class = "inputStyle" }) #Html.ValidationMessageFor(x => x.Notes)
</div>
</div>
<div class="form-actions2 clearfix">
<input type="submit" class="btn btn-block" value="Create" data-ajax="false" id="btnFormSubmit" />
</div>
}
<script type="text/javascript">
$.validator.unobtrusive.parse("#frmCreate");
</script>
The problem is when user submit the form the controller called twice. First time it return the partial view and then again it calls and then jQuery Mobile change the page. I am Using MVC4 with jQuery Mobile 1.1.0
(please note that create.cshtml (desktop ver) works fine but create.Mobile.cshtml (mobility ver) havng this problem)
Do not submit the form, use $("#myForm").serialize() as ajax data.