I use The MVC3 Helper to generate my Ajax form like this:
#using (Ajax.BeginForm("Attended", "Lesson", new AjaxOptions
{
HttpMethod = "GET",
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = "mdl" + item.ID
}))
{
#Html.HiddenFor(modelItem => item.ID);
#Html.CheckBox("Attended", item.Attended, new { OnChange = "javascript:this.form.submit()"});
}
I just don't find the proper way to submit the Form on the change event of the checkbox.
I don't want my users to click the submit button.
The HTMLAttribute works, but on the change a postback happens instead of an ajax request.
Does anybody know the answer?
First, create a submit button inside your form, and hide it by setting the attribute style="display:none;". Then, instead of using this.form.submit() in your onchange event, use the following:
$(this).parents('form:first').find(':submit')[0].click();
This will invoke the jquery.unobtrusive-ajax.js script, and complete your Ajax submission.
this may help
#Html.CheckBox("Attended", item.Attended, new { OnChange = "submitForm"});
function submitForm(e)
{
document.forms[0].submit();
}
What about using jQuery to trigger the submit? Like in this answer How to post ASP.NET MVC Ajax form using JavaScript rather than submit button
Using the .change() event instead of the .click() event the jQuery part would look something like this:
$(function() {
$('form#ajaxForm').find('input.submit').change( function() {
$('form#ajaxForm').trigger('submit');
});
}
#using (Ajax.BeginForm("Attended", "Lesson", new { id = Model.Id }, new AjaxOptions
{
HttpMethod = "GET",
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = "mdl" + item.ID
}, new { id = "ajaxForm" } ))
{
#Html.HiddenFor(modelItem => item.ID);
#Html.CheckBox("Attended", item.Attended, new { #class = "submit"});
}
This is totally untested code so beware of typos :)
Forms are the classical way of sending a request - therefore it is POST - your GET setup is overruled by that in onChange - submits will always clear the content and replaced with server content - i do some javascript to send using AJAX - cannot see that, so I presume that it does exactly that. your OnChange should execute this AJAX function instead ...
Hmm, what actually worked for me, even on cell phones, which was a problem area, was the following, in my cshtml file for a Partial View. It also includes code to grey out the button and write "Saving..." until the view posts back, which avoids people pounding on the submit button when they get impatient for slow SQL Servers.
<div id="myFutureDayEdit">
<script type="text/javascript">
$(document).ready(function () {
$("#submitFutureDayEditVisibleButton").click(function () {
$(this).prop('disabled', true);
$("#myUserMessage").html("Saving...");
$("#myUserMessage").show();
document.getElementById("submitFutureDayEditHiddenButton").click();
});
});
</script>
#Html.ValidationSummary(true)
#using (Ajax.BeginForm("SaveFutureDayEdit", "Member", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "myFutureDayEdit" }))
{ ... bla bla bla
and
<input id="submitFutureDayEditVisibleButton" type="button" value="Save Changes" />
<input id="submitFutureDayEditHiddenButton" style="display:none;" type="submit" value="SC" />
<div id="myUserMessage">
#if (Model.UserMessage != null)
{ #Model.UserMessage }
</div>
<input type="hidden" id="bUnsavedChanges" name="bUnsavedChanges" value="false" />
}
</div>
<div id="hahuloading">
<div id="hahuloadingcontent">
<p id="hahuloadingspinner">
Saving...
</p>
</div>
</div>
Related
I have a partial view that is not updating just the partial, it redirects to the action for the entire page.
In the partial view, _registerAccount.cshtml, that contains a post request to register, the request is made via Ajax in a view named _registerAccount as so:
#model LoginDemo.Models.LdapAccountModel
#using (Ajax.BeginForm("RegisterLdapAccount", "Account", new AjaxOptions
{
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace
}))
{
#Html.ValidationSummary()
#Html.LabelFor(x => Model.Email) #Html.TextBoxFor(x => Model.Email, new { id = "reg-ytu-email" })
<br />
#Html.LabelFor(x => Model.Password) #Html.PasswordFor(x => Model.Password, new { id = "reg-pw" })
<input type="submit" value="Register" class="btn" />
}
In the parent page, Register.cshtml I have:
#model LoginDemo.Models.RegisterModel
...
<div class="panel hide register-type register-ytu">
#Html.Partial("_registerAccount")
</div>
In the Account Controller the ajax request goes to the RegisterAccount action:
[HttpPost]
public async Task<ActionResult> RegisterLdapAccount(LdapAccountModel model)
{
if (model.exists()) // pseudo code
{
return Json(new {foo: "bar"}); // return address to redirect to
}
else
{
ModelState.AddModelError("", "You must have a valid account.");
return PartialView(model); // return error
}
}
The problem I have is that whatever gets returned wipes out the entire page as opposed to updating just the partial within the parent page. That is, if successful the JSON return only returns the JSON, if failed the partial view return only returns the partial.
n.b. I have <add key="UnobtrusiveJavaScriptEnabled" value="true" /> in my web.config.
Amend the following code as follows:
#using (Ajax.BeginForm("RegisterLdapAccount", "Account", new AjaxOptions
{
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "updatearea",
Amend the div to add the id:
<div id="updatearea" class="panel hide register-type register-ytu">
#Html.Partial("_registerAccount")
</div>
Now make sure you have unobtrustive ajax as a script on the page if you don't already.
<script type="text/javascript" src="#Url.Content("/scripts/jquery.unobtrusive-ajax.min.js")"></script>
To add this script it must be in the scripts folder for your project.
Amend the controller so that you are loading the correct partial view, if you don't state the name of the partial view the partial view loaded will be whatever matches the name of the action, if no partial view matches the name of the action no partial view will be loaded. So explicitly state which partial view you want to load like this:
return PartialView("_RegisterAccount", model)
I want to know if there is a better way to accomplish what I am doing or if my current approach is ok. My current approach is giving me a little trouble so I need to see what I can do about it all.
In my MVC web application, I have dropdown lists which are searchable (handled by KendoUI Widgets) and I allow the user to add missing data to the database table which serves those dropdown lists.
Example of Widget
#(Html.Kendo().DropDownList()
.Name("Manufacturer")
.Filter("contains")
.OptionLabel("-- Select --")
.DataTextField("ManufacturerName")
.DataValueField("ManufacturerName")
.NoDataTemplate("No Data Add Manufacturer")
.DataSource(source => {
source.Read(read => {
read.Action("GetManufacturers", "Cars");
}).ServerFiltering(false);
}))
The data is added via an ajax form in a partial view which is displayed using a bootstrap 4.0 modal trigger by a button in the no data template (see above example).
These dropdown lists appear in both Create and Edit views, in the Create view they work fine and as expected but within the Edit views, they have dictionary errors.
Create View
#model MyProject.Models.Cars
#using (Ajax.BeginForm("Create", "Cars", new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "NotifySuccess",
OnFailure = "NotifyFailure"
},
new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
...Form goes here with widgets etc
}
#Html.Partial("_Manufacturer")
Popup form partial view
#model MyProject.Models.Manufacturer
<div class="modal fade" id="modal_addManufacturer">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
#using (Ajax.BeginForm("AddManufacturer", "Cars", new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "Success",
OnFailure = "Fail"
}, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<div class="form-group">
#Html.LabelFor(l => l.ManufacturerName, new { #Class = "form-label" })
#Html.TextBoxFor(i => i.ManufacturerName, new { #Class = "form-control" })
<input type="submit" value="Add" />
<input type="reset" value="Reset" />
</div>
}
</div>
</div>
</div>
</div>
These errors seem to stem from the fact that the Edit method in the controller passes an Id parameter. These leads me to the most obvious question, is this approach correct? Should I be using ajax forms in modals to create data on the fly like this especially when the models they use are causing problems when the Id parameter is used on views such as edit.
Can anyone offer some guidance on what I can do about this?
I am trying to achieve the same result as mentioned by the OP in this post However when I try to render partial view by checking if it was an AJAX request in my Index action, its evaluating to false.
My Index View:
#using (Ajax.BeginForm("Index", "Home",
new AjaxOptions()
{
HttpMethod = "GET",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "restaurantList"
}))
{
<input type="search" name="searchTerm" />
<input type="submit" value="Search By Name" />
}
#Html.Partial("_Restaurant",Model)
My Partial View:
<div id="restaurantList" style="border:2px dotted red; padding-left:2em; margin-top:4px;">
#foreach (var item in Model)
{
<div>
<h4>#item.Name</h4>
<div>#item.City, #item.Country</div>
<div>#item.CountOfReviews</div>
<hr />
</div>
}
</div>
My Index Action:
public ActionResult Index(string searchTerm = null)
{
var model = ...//Building model object here
if (Request.IsAjaxRequest())
{
return PartialView("_Restaurant", model);
}
return View(model);
I would prefer not to dive into use of any jQuery or javascript as I am in the process of learning ASP.NET MVC, and would want to know why the approach I took is not working? The second answer by Dennis, in the post that I referenced also suggested similar approach.
Could someone kindly tell me what I am doing wrong?
Thanks
This is just an example how you can load view from AJAX without page refresh, it may help you.
It send text value to controller by ajax call and load that value in other view which replace main view, if you don't want to replace main view then you can take other div instead same div to load content.
Controller:
public ActionResult Index()
{
return View();
}
[HttpPost]
public PartialViewResult TestAjax(string Name)
{
ViewBag.Name = Name;
return PartialView();
}
Index.cshtml:
<input type="button" id="btnSearch" class="btn btn-warning" style="height:35px;width:120px" value="Search"/>
<label>Name:</label><input type="text" id="txtName" name="txtName" />
<script>
$('#btnSearch').click(function () {
$.ajax({
url: '#Url.Action("TestAjax", "Home")',
data: { Name: $("#txtName").val() },
type: 'POST',
success: function (data) {
$("#divContent").html(data);
}
});
});
</script>
TestAjax.cshtml:
#ViewBag.Name
As #StephenMuecke pointed out in his comments, the libraries not being loaded correctly was the problem. While creating a new bundle of all libraries and adding it in the BundkeConfig.cs I had missed ~/Scripts/jquery.unobtrusive-ajax.js*. Got it working now.
I am trying to validate my form without using Unobtrusive Validation becauase my validation is a little more complicated than average. What is needed to accomplish this? Just include the Validation.js script into my file and writing out the jquery code? That is what I have accomplished so far...
$(document).ready(function () {
$("#formSearchByMRN").validate({
rules: {
MRN: { required: true, minLength: 6 }
},
messages: {
MRN: 'Please Enter a Valid MRN'
}
});
});
However, whenever I submit my form nothing is validated? Here is my form...
#using (Html.BeginForm("SearchByMRN", "SearchPatients", FormMethod.Post, new { id = "formSearchByMRN" }))
{
<p>
<ul>
<li>#Html.Label("MRN#", new { #for = "MRN" })<br />#Html.TextBox("MRN","", new { id = "MRN" })</li>
<li>#Html.Label("MRNDrop", new { #for = "MRNDrop" })<br /> #Html.DropDownList("MRNDrop", (List<SelectListItem>)TempData["MRNLIST"], new { id = "MRNDrop" })</li>
</ul>
</p>
<input type="submit" value="Search by MRN" id="submitMRN"/>
}
What am I missing. I have my jquery Valition script in my _layout.cshtml file.
System I working on is CMS where you insert templates like Contact form template and save that to database. This template is coded against server side to process data.
Now my "contentDiv" within form where all the templates were insert and saved than showed on the page withint form tag wrapped like
#using (Html.BeginForm("Edit", "Home", FormMethod.Post, new { id = "first" }))
{
#Html.Hidden("someId", #Model.PageId)
}
<div id="contentDiv" style="width:100%">#Html.Raw(Model.Html)</div>
Above form is than saved as
$(function () {
$("form#first").submit(function (e) {
e.preventDefault();
var viewmodel = {
Id: $("#someId").val(),
Html: $("#contentDiv").val()
};
$.ajax({
url: $(this).attr("action"),
type: "POST",
data: JSON.stringify(viewmodel),
dataType: "json",
contentType: "application/json; charset=utf-8",
beforeSend: function () { $("#status").fadeIn(); },
complete: function () { $("#status").fadeOut(); },
success: function (data) {
var message = data.Message;
},
error: function () {
}
});
});
});
notice that I moved "contentDiv out of form tag as my contact form which is wrapped in a form tag can not be nested within id=first form.
Is there a solution to form nesting? . If not than
My another question is
contentDiv is not wrapped up in form tag that means if client browser has javascript disabled than he wont be able to post contentDiv data to server and form will be of no use.
What to do?
If I don't move contentDiv out of form tag than than after inserting template the structure will be nesting of forms
#using (Html.BeginForm("Edit", "Home", FormMethod.Post, new { id = "first" }))
{
<form id="contactform" action="/Home/Email" method="post" >
<div class="clear" style="padding-bottom:10px;"></div>
<div class="formCaption">Full Name</div>
<div class="formField"><input id="fullName" name="fullName" class="standardField" /></div>
<div><input id="sendBtn" value="Send" type="button" /></div>
</form>
}
I didn't understand from your description why the html needs to be outside the form. Also you should not use the .val() method for divs. You should use .html():
var viewmodel = {
Id: $("#someId").val(),
Html: $("#contentDiv").html()
};
Of course because you are using javascript to fetch the html which is outside of the main form if client browser has javascript disabled the form will be of no use. Only if you move the html inside the main form would this work without javascript:
#using (Html.BeginForm("Edit", "Home", FormMethod.Post, new { id = "first" }))
{
#Html.HiddenFor(x => x.PageId)
#Html.HiddenFor(x => x.Html)
<input type="submit" value="Edit" />
}
<!--
You could still keep the div for preview or something but don't make
any use of it when submitting.
-->
<div id="contentDiv" style="width:100%">
#Html.Raw(Model.Html)
</div>