Form+Ajax doesn't work properly - javascript

Form+Ajax -> Results on exact DIV
3 hours, 53 minutes ago|LINK
Hi,
I need to visualize my partialView (results after a form submission) in a DIV.
I have the following files:
View Man_por.cshtml
...
<div class="col-md4" id="divTabPortfolios">
enter code here#{Html.RenderAction("Load_portfoliosPartial","Management_portfolios");}
<div>
<div class="col-md4" id="divTabPortfolio">
<div>
...
View Load_portfolios_partial
<script src="myscript.js" type="text/javascript"></script>
....
...
#using ( # Html.BeginForm() )
{
....
...
<button type="submit" class=".." value="Open"/>
}
Script MyScript.js
$(function () {
$('form').submit(function () {
if ($(this).valid()) {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
$('#divTabPortfolio').html(result);
}
});
}
return false;
});
});
When it shows the result it open entire page and not a partial view (_layout.cshtml+Page) etc.. and it doesn't update the specified DIV.
How could i solve it?

Use #using (Ajax.beginForm()) instead of #using (Html.beginForm().
MVC supports Ajax forms out-of-the-box.
You then provide the action, controller and selector (UpdateTargetId is set to the id of the panel to update) like this:
<div id="divTabPortfolio">
#using (Ajax.BeginForm("SomeAction", "YourController", new { id = optionalParameters }, new AjaxOptions() { HttpMethod = "Post", UpdateTargetId = "divTabPortfolio" }))
{
}
</div>
No need for your own jQuery/Ajax for this sort of basic Ajax post-backs in MVC/Razor.
So long as your action method returns a PartialView you don't need to do anything else.
As suggested, if you could post more of the page it would help provide specifics

Related

How to run JavaScript code on Success of Form submit?

I have an Asp.Net MVC web application. I want to run some code on the successful response of the API method which is called on form submit.
I have the below Code.
#using (Html.BeginForm("APIMethod", "Configuration", FormMethod.Post, new { #class = "form-horizontal", id = "formID" }))
{
}
$('#formID').submit(function (e) {
$.validator.unobtrusive.parse("form");
e.preventDefault();
if ($(this).valid()) {
FunctionToBeCalled(); //JS function
}
}
But FunctionToBeCalled() function gets called before the APIMethod(), but I want to run the FunctionToBeCalled() function after the response of APIMethod().
So I made the below changes by referring this link. But now the APIMethod is getting called twice.
$('#formID').submit(function (e) {
$.validator.unobtrusive.parse("form");
e.preventDefault();
if ($(this).valid()) {
//Some custom javasctipt valiadations
$.ajax({
url: $('#formID').attr('action'),
type: 'POST',
data: $('#formID').serialize(),
success: function () {
console.log('form submitted.');
FunctionToBeCalled(); //JS function
}
});
}
}
function FunctionToBeCalled(){alert('hello');}
So I am not able to solve the issue.
If you want to execute some work on success, fail, etc. situation of form submission, then you would need to use Ajax call in your view. As you use ASP.NET MVC, you can try the following approach.
View:
$('form').submit(function (event) {
event.preventDefault();
var formdata = $('#demoForm').serialize();
//If you are uploading files, then you need to use "FormData" instead of "serialize()" method.
//var formdata = new FormData($('#demoForm').get(0));
$.ajax({
type: "POST",
url: "/DemoController/Save",
cache: false,
dataType: "json",
data: formdata,
/* If you are uploading files, then processData and contentType must be set to
false in order for FormData to work (otherwise comment out both of them) */
processData: false, //For posting uploaded files
contentType: false, //For posting uploaded files
//
//Callback Functions (for more information http://api.jquery.com/jquery.ajax/)
beforeSend: function () {
//e.g. show "Loading" indicator
},
error: function (response) {
$("#error_message").html(data);
},
success: function (data, textStatus, XMLHttpRequest) {
$('#result').html(data); //e.g. display message in a div
},
complete: function () {
//e.g. hide "Loading" indicator
},
});
});
Controller:
public JsonResult Save(DemoViewModel model)
{
//...code omitted for brevity
return Json(new { success = true, data = model, message = "Data saved successfully."
}
Update: If SubmitButton calls a JavaScript method or uses AJAX call, the validation should be made in this method instead of button click as shown below. Otherwise, the request is still sent to the Controller without validation.
function save(event) {
//Validate the form before sending the request to the Controller
if (!$("#formID").valid()) {
return false;
}
...
}
Update your function as follows.
$('#formID').submit(function (e) {
e.preventDefault();
try{
$.validator.unobtrusive.parse("form");
if ($(this).valid()) {
$.ajax({
url: $('#formID').attr('action'),
type: 'POST',
data: $('#formID').serialize(),
success: function () {
console.log('form submitted.');
FunctionToBeCalled(); //JS function
}
});
}
}
catch(e){
console.log(e);
}
});
Check the browser console for fetching error. The above code will prevent of submitting the form.
I think line $.validator.unobtrusive.parse("form") were throwing error.
For that use you need to add the following jQuery libraries.
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.9/jquery.validate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"></script>
I think you should remove razor form tag if you want to post your form using ajax call and add post api URL directly to ajax request instead of getting it from your razor form tag using id:
Here is the revised version of your code :
<form method="post" id="formID">
<!-- Your form fields here -->
<button id="submit">Submit</button>
</form>
Submit your form on button click like:
$('#submit').on('click', function (evt) {
evt.preventDefault();
$.ajax({
url: "/Configuration/APIMethod",
type: 'POST',
dataType : 'json',
data: $('#formID').serialize(),
success: function () {
console.log('form submitted.');
FunctionToBeCalled(); //JS function
}
});
});
function FunctionToBeCalled(){alert('hello');}
You need to use Ajax.BeginForm, this article should help [https://www.c-sharpcorner.com/article/asp-net-mvc-5-ajax-beginform-ajaxoptions-onsuccess-onfailure/ ]
The major thing here is that I didn't use a submit button, I used a link instead and handled the rest in the js file. This way, the form would nver be submitted if the js file is not on the page, and with this js file, it initiates a form submission by itself rather than th form submitting when the submit button is clicked
You can adapt this to your solution as see how it respond. I have somthing like this in production and it works fine.
(function() {
$(function() {
var _$pageSection = $('#ProccessProductId');
var _$formname = _$pageSection.find('form[name=productForm]');
_$formname.find('.buy-product').on('click', function(e) {
e.preventDefault();
if (!_$formname.valid()) {
return;
}
var formData = _$formname.serializeFormToObject();
//set busy animation
$.ajax({
url: 'https://..../', //_$formname.attr('action')
type: 'POST',
data: formData,
success: function(content) {
AnotherProcess(content.Id)
},
error: function(e) {
//notify user of error
}
}).always(function() {
// clear busy animation
});
});
function AnotherProcess(id) {
//Perform your operation
}
}
}
<div class="row" id="ProccessProductId">
#using (Html.BeginForm("APIMethod", "Configuration", FormMethod.Post, new { #class = "form-horizontal", name="productForm" id = "formID" })) {
<li class="buy-product">Save & Proceed</li>
}
</div>

Main view stacks on the same page after calling partial view

I have this action that returns different partial view based on the selected value from the drop down list.
Controller:
[HttpPost]
public ActionResult Foo(SomeViewModel VM)
{
var model = VM
if (Request.IsAjaxRequest())
{
if (model.SelectedValue == 1 || model.SelectedValue == 2 || model.SelectedValue == 3)
{
// ...
return PartialView("PartialView1", model);
}
else if (model.SelectedValue == 4)
{
// ...
return PartialView("PartialView2", model);
}
else (model.SelectedValue == 5)
{
// ...
return PartialView("PartialView3", model);
}
}
return View(model);
}
Main View:
<script src="~/Scripts/jquery-3.2.1.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
<div>
<h2>Paint Computation</h2>
#using (Ajax.BeginForm("Foo", "Controller",
new AjaxOptions
{
HttpMethod = "POST",
UpdateTargetId = "Result"
}))
{
<div class="col-md-10">
<h5>Type of Paint</h5>
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.DropDownListFor(m => m.SelectedValue, new SelectList(Model.PaintType, "Value", "Text"),
"Please Select", htmlAttributes: new { #class = "form-control" })
</div>
<br />
// Some HTML helpers
<input type="submit" value="Compute" class="btn btn-default" id="Submit" />
</div>
}
</div>
//This is how I render my partial view using jQuery in my main View:
<div id="Result">
<hr />
</div>
<script type="text/javascript">
$(document).ready(function () {
$('#Submit').click(function () {
$('#Result').load('/Controller/Foo');
});
});
</script>
Whenever I clicked the button, the partial view appears, but when I clicked it again for the 3rd or 4th time, the main view content stacks on the same main view. I tried to use the inspect element and that's how I determined that it stacks the same main view elements.
Is my way of calling the partial view is right? As much as possible I want to use ajax for calling the partial view every time the button is clicked. Please guide me to correct it. Thanks.
Here's the of the problem.
<script type="text/javascript">
$(document).ready(function () {
$('#Submit').click(function () {
$.ajax({
type: 'POST',
url: '/Controller/Foo',
cache: false,
contentType: "application/html; charset=utf-8",
dataType: 'html',
success: function (result) {
$('#Result').html(result);
}
});
});
});
</script>
Now it works. I changed my code and use the code above. I use .html() rather than .append() or .replaceWith(). Now every time i click the button, it changes the <div id = "Result> content.

Autocomplete on Html.TextBox won't work

So, I've searched alot and went through alot of tutorials and even though I do everything exactly as in the tutorial, I just can't seem to get it working. Funny thing is, I have been involved in a project where we used the exact same solution and it worked.
I've got a textbox in my forum where users can search for threads in all categories where I am using ajax to show the result in a div in form of a partial view. This is working.
The problem is that I want the thread subjects that are containing the current search term to show up (in form of a normal string) while the user is typing, but I can't seem to get the implementation of autocomplete right. By the way I am retrieving my information from a MSSQL-database.
This is the javascript that I am using to autocomplete (which is not working) and below that you can see my Ajax-form that I use for the search (that works):
<link href="~/Content/jquery-ui.min.css" rel="stylesheet" />
<script src="~/Scripts/jquery-ui.min.js"></script>
#*Scripts for Ajax to show the partial view in the div with id "partialThreads" at request*#
<script src="~/Scripts/jquery-2.2.1.min.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
<script type="text/javascript">
$(function () {
$("#txtSearch").autocomplete({
source: '#Url.Action("GetThreadsBySearch", "Forum")'
});
});
</script>
#using (#Ajax.BeginForm("Threads", new AjaxOptions() { UpdateTargetId = "partialThreads", InsertionMode = InsertionMode.Replace, HttpMethod = "POST" }))
{
#Html.AntiForgeryToken()
<p><strong>Search for thread in all categories</strong></p>
#Html.TextBox("searchTerm", null, new { id = "txtSearch", style = "width: 1000px" })
<input type="submit" value="Search" />
}
Here is the div where I show the results of the search in form of a partial view:
<div id="partialThreads">
</div>
Here is the action method that I am using for my ajax-form search (the working one):
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Threads(string searchTerm)
{
var model = string.IsNullOrWhiteSpace(searchTerm)
? new List<ThreadsListModel>()
: _threadRepo.GetThreadsBySearch(searchTerm).OrderByDescending(x => x.DateCreated).ToList();
return PartialView("_Threads", model);
}
And here is the method that I use to retrieve the information to my autocomplete (I've tried setting a break point on it, it doesn't even break):
public JsonResult GetThreadsBySearch(string term)
{
var threadNames = _threadRepo.GetThreadsBySearch(term).Select(x => x.Subject).ToList();
return Json(threadNames, JsonRequestBehavior.AllowGet);
}
Note that I use the same db-query to search with the form and for the autocomplete (only difference would be that I select the threadnames as a List in the GetThreadsBySearch method. So that can't be the problem (?). Here is query-method in case you want to have a look:
public ICollection<ThreadsListModel> GetThreadsBySearch(string subject)
{
using (var context = new ForumContext())
{
return
context.Threads.Where(x => x.Subject.ToLower().Contains(subject.ToLower()) && x.IsActive)
.Select(x => new ThreadsListModel()
{
ID = x.ID,
DateCreated = x.DateCreated,
CreatedBy = x.CreatedBy,
Subject = x.Subject,
PostsCount = x.Posts.Count
}).Distinct().ToList();
}
}
Also, I am using Visual Studio 2015 (.NET 4.5.2) MVC 5. I hope that I haven't forgot to write down any helpful information.
Your scripts are in the wrong order and jquery needs to be before jquery-ui (and also ensure that you do not have any duplicated scripts)
$("#MainContent_txtCountry").autocomplete({
source: function (request, response) {
var param = { keyword: $('#MainContent_txtCountry').val() };
$.ajax({
url: "Default.aspx/GetCountryNames",
data: JSON.stringify(param),
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8",
dataFilter: function (data) { return data; },
success: function (data) {
response($.map(data.d, function (item) {
return {
value: item
}
}))
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus);
}
});
},
});

How to retain an injected partial view after page refresh in asp.net mvc

I am using ASP.NET MVC 4 and jQuery. I have a button control on my view. When it is clicked it "injects" a partial view into my view. When I refresh the page then the partial view is gone.
My HTML markup:
<button id="RetrieveButton" type="button">Retrieve</button>
<div id="RuleDetails">
<div class="main-content">
<p>Some text.</p>
</div>
</div>
My jQuery to return the partial view with an AJAX call to return the HTML:
$('#RetrieveButton').click(function () {
$.ajax(
{
type: 'POST',
url: '#Url.Action("GetRuleDetails")',
data: {
systemCode: $('#SystemCodes').val()
},
dataType: "html",
success: function (result) {
alert('success');
var domElement = $(result);
$("#RuleDetails").html(domElement);
},
error: function (result) {
alert('error');
}
});
});
My action method:
public ActionResult GetRuleDetails()
{
RuleViewModel viewModel = new RuleViewModel();
return PartialView("_RuleInformation", viewModel);
}
My partial view:
#model MyProject.ViewModels.Rules.RuleViewModel
<div class="main-content">
<h2>Rule Details</h2>
</div>
I need this "injected" partial view to remain there if I were to refresh the page. Currently it "resets" if I were to refresh it, and the partial that was injected is gone.
It will not render that partial view again as it is does not remembers clicked state of button.
One of the ways to achieve what you are looking for is by using sammy.js
On click of button you can set the hashurl using sammy.js (e.g.: '#/partialview') and on page refresh hashurl part stays intact (but does not go to server). And then you can manipulate the client code accordingly
Take sammy.js reference in your page.
Intialize sammy like below
var app = $.sammy('body', function (context){
this.get('#/PartialView1', function () {
fnLoadPartialView();
});
});
change Retrieve to with href='PartialView1'
function fnLoadPartialView (){
$.ajax(
{
type: 'POST',
url: '#Url.Action("GetRuleDetails")',
data: {
systemCode: $('#SystemCodes').val()
},
dataType: "html",
success: function (result) {
alert('success');
var domElement = $(result);
$("#RuleDetails").html(domElement);
},
error: function (result) {
alert('error');
}
});
}
5.
$('#RetrieveButton').click(function () {
fnLoadPartialView ();
});

MVC3 AJAX passing data to controller. It's being submitted twice

So I have a table that gets transformed to an array using:
var result = $("#enrolledStudents").sortable('toArray');
But when I go a head an pass that into my controller like so:
$("#update-enroll").click(function () {
var result = $("#enrolledStudents").sortable('toArray');
$.ajax({
url: '#Url.Action("Enrollment", "Classroom")',
data: { students: result },
type: 'POST',
traditional: true
});
});
My debugging breakpoint gets set off twice, causing issues to arise. What is the proper way to submit data to my controller on POST?
Per my comments, there are a couple things that could be causing this.
You have have the unobtrusive file(s) loaded multiple times
Your form has an action method defined, and your button is inside the form tag as a submit button. This will submit the form, and then the click will also submit the form - see example
Example
<form action="/somerowout/someaction">
<input type="text" id="text1"/>
<input type="text" id="text1"/>
<input type="submit" />
</form>
If you need to validate a value on your form before posting, don't hook up an additional Ajax call. Your javascript will look something like:
$(document).ready(function () {
$("form").submit(function(){
var result = $("#enrolledStudents").sortable('toArray');
if(result == null){
//do something to show validation failed
return false;
}
return true;
});
});
And your form code would then look something like:
#using (#Ajax.BeginForm(new AjaxOptions { })) {
<input type="text" id="text1"/>
<input type="text" id="text1"/>
<input type="submit" />
}
If you want to use Ajax rather than the Html Helpers, use a div instead of a form, and you won't get a duplicate post. Here's how you could achieve this:
<div id="enrolledStudents">
<--! your elements -->
<button id="saveStudents">Save</button>
</div>
JavaScript
$(document).ready(function () {
$("saveStudents").click(function(){
var result = $("#enrolledStudents").sortable('toArray');
if(result !== null){ /* do some kind of check here. */
$.ajax({
url: '#Url.Action("Enrollment", "Classroom")',
data: { students: result },
type: 'POST',
traditional: true,
success : function(data) {
if (data.status) {
window.location = data.route;
}
}
})
} else {
/* notify ui that save didn't happpen */
}
});
});
Example Controller Action
When posting your data using Ajax, here's an example of how to pass the route
[HttpPost]
public ActionResult SomethingPost(SomeModel model) {
if (Request.IsAjaxRequest()) {
var json = new {
status = true,
route = #Url.RouteUrl("MyRouteName", new { /* route values */ })
};
return Json(json, JsonRequestBehavior.AllowGet);
}
}
Are you sure you are preventing the default behaviour (form POSTING) of the submit button ? use preventDefault to do so.
$("#update-enroll").click(function (e) {
e.preventDefault();
//rest of the code
});
EDIT : As per the comment
To do the redirect in the ajax handler, you need to return the URL to be redirected in a JSON Response back to the calle.
[HttpPost]
public ActionResult Classroom(string students)
{
//do some operaton
if(Request.IsAjax())
{
//This is an Ajax call
return Json(new
{
Status="Success",
NewUrl = Url.Action("Index","Home")
});
}
else
{
//Normal request. Use RedirectToActiom
return RedirectToAction("Index","Home");
}
}
Now in your ajax call check the JSON result and do the redirect.
$.ajax({
url: '#Url.Action("Enrollment", "Classroom")',
data: { students: result },
type: 'POST',
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (data) {
if(data.Status=="Success")
{
window.location.href = data.Newrl;
}
else
{
alert("some error");
}
}
});
Check if you don't have the jquery files loaded twice. I had this behavior and the problem was files loaded twice.

Categories

Resources