I'm typing this question away from my computer so I don't have the exact code, but the question might be straightforward enough without it.
When I have a submit button directly within an Ajax form and I click the button directly to submit, everything works fine, and as expected. The Ajax.Form POSTs back to the controller which returns a partial view that is rendered inside the current View that I have.
But what I need is for a button to be clicked in the Ajax.Form, and for a JavaScript function to run. The JavaScript function will do some vaildation which decides whether to submit the Ajax.Form or not.
I have tried putting 2 buttons in the Ajax.Form, a hidden submit button and a regular button. I used the onclick event of the regular button to call my JavaScript function which then called the click method of the hidden submit button. (I have also tried just submitting the Ajax.Form directly with document.forms[formname].submit() )
This sort of works.. But not correctly for some reason. The Ajax.Form POSTs back to the controller but when a partial view is returned from the controller, the partial view is the only thing rendered, and it is rendered as basic html with no css/bootstrap.
What is the difference between actually clicking the submit button and doing so programmatically?
How can Achieve what I am trying to do?
Edit
#using (Ajax.BeginForm("GetInstructorInfo", "Incident", FormMethod.Post, new AjaxOptions { OnBegin = "lookupInstructor();", UpdateTargetId = "InstructorInfo" }, new { #class = "form-inline", role = "form", #id = "instructorInfoForm", #name = "instructorInfoForm" }))
{
//code in here
}
Edit 2 / 3:
<script>
function lookupInstructor()
{
if ($('input[name="Instructors['+userInputInstructor+'].Username'+'"]').length > 0) //Don't allow user to enter multiple instances of the same Instructor
{
document.getElementById("InstructorUsername").value = ''; //clear textbox value
return false;
}
var userInputInstructor = document.getElementById("InstructorUsername").value;
$.ajax({
url: '#Url.Content("~/Incident/LookUpUsername")',
data: { userInput: userInputInstructor },
success: function (result) {
if (result.indexOf("not found") != -1){ //if not found
$("#InstructorNotFoundDisplay").show();
document.getElementById("InstructorUsername").value = ''; //clear textbox value
$('#InstructorInfo').empty();
return false;
}
else {
$("#InstructorNotFoundDisplay").hide();
return true;
}
}
});
}
</script>
You can use the OnBegin() ajax option to call a function that runs before the form is submitted (and return false if you want to cancel the submit). For example
function Validate() {
var isValid = // some logic
if (isValid) {
return true;
} else {
return false;
}
}
and then in the Ajax.BeginForm() options
OnBegin = "return Validate();"
Edit
Based on the edits to the question and the comments, you wanting to call an ajax function in the OnBegin() option which wont work because ajax is asynchronous. Instead, use jQuery.ajax() to submit you form rather than the Ajax.BeginForm() method (and save yourself the extra overhead of including jquery.unobtrusive-ajax.js).
Change Ajax.BeginForm() to Html.BeginForm() and inside the form tags replace the submit button with <button type="button" id="save">Save</button>and handle its .click() event
var form = $('#instructorInfoForm');
var url = '#Url.Action("GetInstructorInfo", "Incident")';
var target = $('#InstructorInfo');
$('#save').click(function() {
if ($('input[name="Instructors['+userInputInstructor+'].Username'+'"]').length > 0) {
....
return; // exit the function
}
$.ajax({
....
success: function (result) {
if (result.indexOf("not found") != -1) {
....
}
else {
$("#InstructorNotFoundDisplay").hide();
// submit the form and update the DOM
$.post(url, form.serialize(), function(data) {
target.html(data);
});
}
}
});
});
Related
In my Rails app, I have a form for voting on various "post" titles. The form has one select element, and submits remotely to a VotesController using rails-ujs. I want to handle response the normal way, in the controller receiving the request, with respond_to do |format|.
One option is adding {:onchange=>'$(this.form).submit();'} to the f.select builder, as other answers have suggested.
However, because form submit takes about 8 seconds, I'd like to add my own handler to either the select onchange, or the form onsubmit (which event doesn't matter to me) to
disable all other forms on the same page
show a modal saying why we're disabling the other forms
only allow one "favorite" vote per user (downgrade previous votes on other titles)
store some data attributes in the select for later handling
The issue i'm having is
if I bind my extra handler to the select change event, i can fire a submit via native rails-ujs, but the browser asks me if I want to leave the current page. I can solve this by adding my own AJAX call to my handler , but I'm trying to use the default Rails controllers and rails-ujs to handle submit. I just want to add an extra handler to change the DOM before the slow response arrives.
if I bind my extra handler to the form submit event, the form does not submit and the binding does not have any effect on elements in the DOM, although there are no console errors.
Here's my code:
# partial appears on PostsController#show
# there are several of these on the page, for voting on post titles
<%= form_with(model: #vote, url: naming_vote_path(naming_id: naming.id),
method: :patch, local: false, id: "cast_vote_#{naming.id}",
class: "naming-vote-form") \
do |f| %>
<%= f.select(:value, menu, {},
{ class: "form-control w-100",
# onchange: "this.form.submit();", # works but does not allow further bindings
data: { role: "change_vote", id: naming.id } }) %>
<% end %>
$(document).ready(function () {
var change_vote_selects = function () {
return $("[data-role='change_vote']");
};
var attach_bindings = function () {
change_vote_selects().on("change", function (event) {
var _this = $(this);
var value = _this.val();
var naming_id = _this.data("id");
_haveVotesChanged = true;
// If setting vote to 3.0, go through all the rest and downgrade any
// old 3.0's to 2.0. Only one 3.0 vote is allowed. Also disable all
// the selects while the AJAX request is pending.
if (value == "3.0") {
change_vote_selects().each(function () {
var _this2 = $(this);
if (_this2.data("id") != naming_id && _this2.val() == "3.0") {
_this2.val("2.0");
}
_this2.attr("disabled", "disabled");
});
}
// modal printed in layout already, add text to it and activate
$('#naming_ajax_progress_caption').empty().append(
$("<span>").text(translations.show_namings_saving + "... "),
$("<span class='spinner-right mx-2'></span>")
);
$("#naming_ajax_progress").modal('show');
_this.parent().submit();
});
// Save initial value in case of error, when we'll need to revert.
change_vote_selects().each(function (event) {
var _this = $(this);
_this.data("old_value", _this.val());
_this.attr("disabled", null);
});
};
// Alert the user if they haven't saved data.
window.onbeforeunload = function () {
if (_haveVotesChanged && !_haveVotesBeenSaved)
return translations.show_namings_lose_changes;
}
attach_bindings();
});
Thanks to this answer, I need to fire a native rails-ujs submit on the form, to submit remotely.
$(document).ready(function () {
var change_vote_selects = function () {
return $("[data-role='change_vote']");
};
var attach_bindings = function () {
change_vote_selects().on("change", function (event) {
var _this = $(this);
var value = _this.val();
var naming_id = _this.data("id");
_haveVotesChanged = true;
// If setting vote to 3.0, go through all the rest and downgrade any
// old 3.0's to 2.0. Only one 3.0 vote is allowed. Also disable all
// the selects while the AJAX request is pending.
if (value == "3.0") {
change_vote_selects().each(function () {
var _this2 = $(this);
if (_this2.data("id") != naming_id && _this2.val() == "3.0") {
_this2.val("2.0");
}
_this2.attr("disabled", "disabled");
});
}
// modal printed in layout already, add text to it and activate
$('#naming_ajax_progress_caption').empty().append(
$("<span>").text(translations.show_namings_saving + "... "),
$("<span class='spinner-right mx-2'></span>")
);
$("#naming_ajax_progress").modal('show');
nativeFormEl = _this.parent()[0]
Rails.fire(nativeFormEl, 'submit')
});
// Save initial value in case of error, when we'll need to revert.
change_vote_selects().each(function (event) {
var _this = $(this);
_this.data("old_value", _this.val());
_this.attr("disabled", null);
});
};
// Alert the user if they haven't saved data.
window.onbeforeunload = function () {
if (_haveVotesChanged && !_haveVotesBeenSaved)
return translations.show_namings_lose_changes;
}
attach_bindings();
});
Really stuck on this one, I've inherited a website that was built using a page builder vomits
I've created a script that guards the downloads on this page (resources) the user must fill out a form and input their details, the form submission works correctly and when it completes I open the resource using window.open(href, '_blank') this works correctly on the first submit but if you try and download a second resource it always returns the first clicked href and opens that.
Here is my code: Im getting all the anchors on the page, looping over them and adding an onClick event listener, when a user clicks the link it opens the modal, then jquery to submit the form. As you can see in the comments the href is logged correctly when outside of the submit function, however when inside the submit function it always reverts back to the first href clicked.
e.g user clicks resource1, submits the form and downloads, user then clicks resource2, submits the form but is directed to resource1 :'(
jQuery(document).ready(function ($) {
const anchors = Array.from(
document.querySelectorAll('.page-id-17757 .elementor-element-7121f28 .elementor-widget-icon-list a')
);
const modal = document.querySelector('#resources-modal');
function getFormData($form) {
var unindexed_array = $form.serializeArray();
var indexed_array = {
data: {},
};
$.map(unindexed_array, function (n, i) {
indexed_array.data[n['name']] = n['value'];
});
return indexed_array;
}
function updateFormResponse(status, anchor) {
if (status == 200) {
$('.form-response').html('Success.');
modal.close();
$('.form-response').html('');
$('#resources-submit').prop('disabled', false);
} else {
$('.form-response').html('There has been an error, please refresh the page and try again');
$$('#resources-submit').prop('disabled', false);
}
}
anchors.forEach((anchor) => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
modal.showModal();
let href = e.target.parentElement.href;
$('.resources-download').submit(function (e) {
console.log(e);
e.preventDefault();
e.stopImmediatePropagation();
let form = $(this);
$('#resources-submit').prop('disabled', true);
let formData = getFormData(form);
$.ajax({
url: '/wp-content/themes/hello-elementor/raisley/resources-download.php',
type: 'POST',
data: formData,
dataType: 'json',
complete: function (data) {
updateFormResponse(data.status, href);
if (data.status == 200) downloadResource();
},
});
});
console.log(href); // this logs the correct href
function downloadResource() {
console.log(href); // logs incorrect href, always returns the first clicked href
window.open(href, '_blank');
}
});
});
});
I'm really struggling with this one, need some pro help please!
Thanks,
I've looked around and none of the other similar posts have helped me. I have built an AJAx based form in Yii 2 and jQuery and it seems it submits the form twice.
My form:
$form = ActiveForm::begin([
'id' => 'company_form',
'ajaxDataType' => 'json',
'ajaxParam' => 'ajax',
'enableClientValidation' => false
]);
My JS code:
$(document).ready(function() {
/* Processes the company signup request */
$('#company_form').submit(function() {
signup('company');
return false;
});
})
function signup(type) {
var url;
// Set file to get results from..
switch (type) {
case 'company':
url = '/site/company-signup';
break;
case 'client':
url = '/site/client-signup';
break;
}
// Set parameters
var dataObject = $('#company_form').serialize();
// Run request
getAjaxData(url, dataObject, 'POST', 'json')
.done(function(response) {
//.........
})
.fail(function() {
//.....
});
// End
}
Shouldn't the standard submit be stopped by me putting the return: false; in the javascript code?
Why is it submitting twice?
More Info: However the strange thing is, that only appears to happen the first time; if I hit submit again it only submits once; but if I reload the page and hit submit it will do it twice again.
You may need to change your code like below:
$('#company_form').submit(function(e) {
e.preventDefault();
e.stopImmediatePropagation();
signup('company');
return false;
});
http://api.jquery.com/event.stoppropagation/
http://api.jquery.com/event.stopimmediatepropagation/
Solution common
Next JS will works with any state of 'enableClientValidation':
$('#company_form').on('beforeSubmit', function (e) {
signup('company');
return false;
});
https://yii2-cookbook.readthedocs.io/forms-activeform-js/#using-events
I have the following jQuery code, the point of this code is to create a short time delay, so the AJAX request gets time to execute properly:
$('#form_id').submit(function(e) {
e.preventDefault();
$submit_url = $(this).data('submitUrl');
$submit_url = $submit_url.replace('http://','').replace(window.location.host,'');
if ($(this).data('toBeAjaxSubmitted') == true) {
$.ajax($submit_url, {
type : $(this).attr('method'),
data : $(this).serialize(),
complete : function(data) {
$(this).data('toBeAjaxSubmitted', false);
$('#form_id').submit();
}
});
}
});
What happens is, the form starts off with a submit url that I need to submit to in order for the component to save an entry to the database. But I also need user input to submit directly to a payment gateway URL where the user then makes a payment.
The code above creates the AJAX request, but does not return to normal postback behaviour (via $('#form_id').submit()).
It keeps submitting the form over and over, but never posts to the gateway URL or redirects out.
What am I doing wrong?
The following worked for me after some more debugging:
$('#chronoform_Online_Submission_Step8_Payment').submit(function(e) {
var form = this;
e.preventDefault();
$submit_url = $(this).data('submitUrl');
$submit_url = $submit_url.replace('http://','').replace(window.location.host,'');
if ($(this).data('toBeAjaxSubmitted') == true) {
$.ajax($submit_url, {
type : $(this).attr('method'),
data : $(this).serialize(),
complete : function(data, status) {
}
}).done(function() {
form.submit();
});
}
});
What really put me on the wrong path was that in Chrome's Developer Tools I had the following option enabled 'Disable cache (while DevTools is open)' and this was causing some headaches with inconsistent behaviour between Safari, Firefox (which worked) and Chrome which did not.
What about some fiddling with this approach?
$('#form_id').submit(function(e) {
// closures
var $form = $(this);
var fAjaxComplete = function(data) {
// don't send the ajax again
$form.data('toBeAjaxSubmitted', 'false');
// maybe do some form manipulation with data...
// re-trigger submit
$form.trigger('submit');
};
var oAjaxObject = {
type : $form.attr('method'),
data : $form.serialize(),
complete : fAjaxComplete
};
var sSubmitUrl = $form.data('submitUrl');
// scrub url
sSubmitUrl = sSubmitUrl.replace('http://','').replace(window.location.host,'');
// if ajax needed
if ($form.data('toBeAjaxSubmitted') != 'false') {
// go get ajax
$.ajax(sSubmitUrl, oAjaxObject);
// don't submit, prevent native submit behavior, we are using ajax first!
e.preventDefault();
return false;
}
// if you got here, go ahead and submit
return true;
});
I have a form in a JSP as follows:
<form action = "<c:url value = '/displayVisualisation' />"
title = "${item.visDescription}"
method = "post" onClick = "return confirmRequest('Do you want to change to
another visualisation type?');">
<input class = "text" type = "text" value = "${item.visTypeName}">
</form>
Which calls a Javascript method as follows:
function confirmRequest(questionText) {
var confirmRequest = confirm(questionText);
if (confirmRequest) {
return true;
}
else {
return false;
}
}
To ask the user for a reply to the question asked. However, the confirm prompt appears but does not perform the displayVisualisation action!
Can anyone suggest why or help me implement this correctly?
In other examples, where the action is triggered by clicking a graphic, all is well.
Since you are using onclick, return true; in your confirmRequest function is simply allowing the rest of the clickHandler chain to be executed. I think you also need to explicitly submit the form at this time, in the true case.
Here is one way to do that, using only javascript:
function confirmRequest(questionText) {
var confirmRequest = confirm(questionText);
if (confirmRequest) {
document.forms[0].submit();
return true;
}
else {
return false;
}
}