As the title states my Ajax call is actually causing the form to be submitted to its default action, why? I've never come across this before, all my other ajax calls have never done this.
function newAjax(t,u){ //t = type(post/get), u = url
var resource = null;
if (window.ActiveXObject) {
resource = new ActiveXObject("Microsoft.XMLHTTP");
}
else if (window.XMLHttpRequest) {
resource = new XMLHttpRequest();
resource.overrideMimeType('text/html');
}
resource.open(t,u,false);
resource.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
return resource;
}
function send_newsletter(){
formObj = document.getElementById("news_form");
var inputs = formObj.getElementsByTagName("INPUT");
var parameters = "";
for(i = 0; i < inputs.length; i++){
parameters += inputs[i].name+"="+encodeURI(inputs[i].value);
if(i != inputs.length-1){
parameters += "&";
}
}
var url = "whereitshouldbegoing.com";
var ajax = newAjax("POST",url);
ajax.onreadystatechange = ajaxResult;
ajax.setRequestHeader("Content-length", parameters.length);
ajax.setRequestHeader("Connection", "close");
ajax.send(parameters);
}
It all works fine upto the .send line, which is the bugger which is causing the form to submit aswell(I also have no idea if the ajax request actually gets off).
The send_newsletter function is called from an input type="image" element with onclick="send_newsletter()"
Please don't tell me to use jQuery or another library, as much as I would love to, we can't use any external librarys, corporate guidelines and whatnot.
An input of type "image" will behave the same as a submit button. Use an anchor or button type input to trigger your method.
<input type="button" onclick="send_newsletter()" value="Send" />
<button onlclick="send_newsletter()">... </button>
<img src="... />
Are you using a submit button to call send_newsletter?
onreadystatechange callback function 'ajaxResult' is not called because you're doing a synchronous call to the server:
resource.open(t,u,false);
if you want ajaxResult to be called change it to :
resource.open(t,u,true);
for now that's what I see. You have to provide more info like how do you call send_newsletter?
EDIT:(following author comment)
an INPUT of type image is a graphical submit button.
Related
I'm using Laravel for my application.
I have made a PRINT button on my HTML page which is simply calling a route, to be able to send it throught DOMPDF to print it to PDF.
Print
Now, in my Controller, I would like to get the value of a radio button which has been created in the HTML this way
<div class="col-lg-7 selectie">
<input type="radio" name="factuur_selectie" id="factuur_selectie" value="1" checked> Alle facturen 
<input type="radio" name="factuur_selectie" id="factuur_selectie" value="2"> Betaalde facturen
<input type="radio" name="factuur_selectie" id="factuur_selectie" value="3"> Onbetaalde facturen
</div>
In my controller I can not find the way to get the value of the checkbox, I suppose because I'm not doing a submit ?
How would I be able to get the value of the radio button please?
public function printFacturen(Request $request){
}
I already tried three following ways, but it is not working :
$fields = Input::get('factuur_selectie');
$value = $request->get('factuur_selectie');
$request->input('factuur_selectie');
Bestregards,
Davy
You need to grab the value of factuur_selectie using JavaScript and add it to the generated URL, something like:
var val = document.querySelector('#factuur_selectie:checked').value;
var btn = document.querySelector('.btn.btn-default');
var url = btn.getAttribute('href');
btn.setAttribute('href', url + '?factuur_selectie=' + val);
Then you should be able to retrieve factuur_selectie from your controller.
Probably you are going to need to update the value everytime an option is selected. In that case you can retrieve the value from then event itself:
var btn = document.querySelector('.btn.btn-default');
document.querySelector('.selectie').addEventListener('change', function(event) {
var val = event.target.value;
var url = btn.getAttribute('href');
var pos = url.indexOf('?');
// If URL already contains parameters
if(pos >= 0) {
// Remove them
url = url.substring(0, pos);
}
btn.setAttribute('href', url + '?factuur_selectie=' + val);
});
Here you have a working example.
I have written an Ajax POST to submit a form, but it fails to succeed.
The Ajax POST comes through to the action in the controller which in turn will return a PartialView, which is also made correctly as I can debug this.
The goal is to let the user add a new log, whatever the outcome (failed captcha, failed validation) a Partialview will be returned with the right ViewBag errors messages. Razor takes care of the rest. This way the user will not be redirected to other pages.
When the Ajax succeeds it should put the data in the right <div>. The code is a copy of a working Ajax GET only changing it into a POST and providing the formdate serialized.
tldr; Ajax POST to Action in controller works, the partialview is rendered and returned yet the Ajax failes to succeed making it unable to update the designated <div>
Ajax call:
<script>
$('#add-log').click(function (event) {
event.preventDefault();
$.ajax({
url: $('#add-log').attr('data-url'),
type: 'post',
data: $("#log-form").serialize(),
succes: function (data) {
$('#add-log').attr('data-target').html(data);
console.log("Succes");
}
});
}
</script>
Controller:
[HttpPost, ValidateInput(false)]
[Authorize(Roles = "Student")]
public ActionResult Add(object sender, Log log, string returnURL, bool SendEmail)
{
ViewBag.Vulns = TempData["Vulns"];
//region Captcha: Here we have our Captcha settings
var response = Request["g-recaptcha-response"];
//secret that was generated in key value pair
const string secret = "Just a secret for our captcha, move along";
var client = new WebClient();
var reply = client.DownloadString(string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", secret, response));
var captchaResponse = JsonConvert.DeserializeObject<CaptchaResponse>(reply);
if (ModelState.IsValid && captchaResponse.Success)
{
db.Log.Add(log);
db.SaveChanges();
if (SendEmail)
{
//Emails are sent from here on out, but that's out of the scope
}
}
else
{
if (!captchaResponse.Success)
{
ViewBag.fillcaptcha = "Please fill in the captcha";
}
else
{
ViewBag.Wrong = "Something went wrong please try again";
}
ViewBag.returnUrl = returnURL;
ViewBag.domain = log.DomainId;
return PartialView(log);
}
}
There's more code but I left that out. Most important thing in the controller is just the last IF. I test the ajax by posting an empty log with no captcha resulting in a partialview with the same log and the viewbag.captcha error. This partialview is rendered but somehow ajax doesn't succeed.
I have a form in which I need to call two action methods, one after the other. This is how the flow goes.
First I check if the prerequisite data is entered by the user. If not then I show a message that user needs to enter the data first.
If all the prerequisite data is entered, I call an action method which return data. If there is no data returned then I show a message "No data found" on the same page.
If data is returned then I call another action method present in a different controller, which returns a view with all the data, in a new tab.
The View:
#using (Ajax.BeginForm("Index", "OrderListItems", null, new AjaxOptions { OnBegin = "verifyRequiredData"}, new { #id = "formCreateOrderListReport", #target = "_blank" }))
{
//Contains controls and a button
}
The Script in this View:
function verifyRequiredData() {
if ($("#dtScheduledDate").val() == "") {
$('#dvValidationSummary').html("");
var errorMessage = "";
errorMessage = "<span>Please correct the following errors:</span><ul>";
errorMessage += "<li>Please enter Scheduled date</li>";
$('#dvValidationSummary').append(errorMessage);
$('#dvValidationSummary').removeClass('validation-summary-valid').addClass('validation-summary-errors');
return false;
}
else {
$('#dvValidationSummary').addClass('validation-summary-valid').removeClass('validation-summary-errors');
$('#dvValidationSummary').html("");
$.ajax({
type: "GET",
url: '#Url.Action("GetOrderListReport", "OrderList")',
data: {
ScheduledDate: $("#dtScheduledDate").val(),
Crews: $('#selAddCrewMembers').val(),
Priorities: $('#selPriority').val(),
ServiceTypes: $('#selServiceTypes').val(),
IsMeterInfoRequired: $('#chkPrintMeterInfo').val()
},
cache: false,
success: function (data) {
debugger;
if (data !== "No data found") {
//var newUrl = '#Url.Action("Index", "OrderListItems")';
//window.open(newUrl, '_blank');
return true;
} else {
//Show message "No data found"
return false;
}
}
});
return false;
}
}
The "GetOrderListReport" Action method in "OrderList" Controller:
public ActionResult GetOrderListReport(OrderListModel model)
{
var contract = new OrderReportDrilldownParamDataContract
{
ScheduledDate = model.ScheduledDate
//Setting other properties as well
};
var result = OrderDataModel.GetOrderList(contract);
if (string.IsNullOrWhiteSpace(result) || string.IsNullOrEmpty(result))
{
return Json("No data found", JsonRequestBehavior.AllowGet);
}
var deserializedData = SO.Core.ExtensionMethods.DeserializeObjectFromJson<OrderReportDrilldownDataContract>(result);
// send it to index method for list
TempData["DataContract"] = deserializedData;
return Json(deserializedData, JsonRequestBehavior.AllowGet);
}
The last action method present in OrderListItems Controller, the result of which needs to be shown in a new tab:
public ActionResult Index()
{
var deserializedData = TempData["DataContract"] as OrderReportDrilldownDataContract;
var model = new OrderListItemViewModel(deserializedData);
return View(model);
}
The problem is that I am not seeing this data in a new tab, although I have used #target = "_blank" in the Ajax.BeginForm. I have also tried to use window.open(newUrl, '_blank') as can be seen above. But still the result is not shown in a new tab.
Please assist as to where I am going wrong?
If you are using the Ajax.BeginForm you shouldn't also be doing an ajax post, as the unobtrusive ajax library will automatically perform an ajax post when submitting the form.
Also, if you use a view model with data annotation validations and client unobtrusive validations, then there would be no need for you to manually validate the data in the begin ajax callback as the form won't be submitted if any validation errors are found.
The only javascript code you need to add in this scenario is a piece of code for the ajax success callback. That will look as the one you currently have, but you need to take into account that opening in new tabs depends on the browser and user settings. It may even be considered as a pop-up by the browser and blocked, requiring the user intervention to allow them as in IE8. You can give it a try on this fiddle.
So this would be your model:
public class OrderListModel
{
[Required]
public DateTime ScheduledDate { get; set; }
//the other properties of the OrderListModel
}
The form will be posted using unobtrusive Ajax to the GetOrderListReport of the OrderList controller. On the sucess callback you will check for the response and when it is different from "No data found", you will then manually open the OrderListItems page on a new tab.
This would be your view:
#model someNamespace.OrderListModel
<script type="text/javascript">
function ViewOrderListItems(data){
debugger;
if (data !== "No data found") {
var newUrl = '#Url.Action("Index", "OrderListItems")';
//this will work or not depending on browser and user settings.
//passing _newtab may work in Firefox too.
window.open(newUrl, '_blank');
} else {
//Show message "No data found" somewhere in the current page
}
}
</script>
#using (Ajax.BeginForm("GetOrderListReport", "OrderList", null,
new AjaxOptions { OnSucces= "ViewOrderListItems"},
new { #id = "formCreateOrderListReport" }))
{
#Html.ValidationSummary(false)
//input and submit buttons
//for inputs, make sure to use the helpers like #Html.TextBoxFor(), #Html.CheckBoxFor(), etc
//so the unobtrusive validation attributes are added to your input elements.
//You may consider using #Html.ValidationMessageFor() so error messages are displayed next to the inputs instead in the validation summary
//Example:
<div>
#Html.LabelFor(m => m.ScheduledDate)
</div>
<div>
#Html.TextBoxFor(m => m.ScheduledDate, new {id = "dtScheduledDate"})
#Html.ValidationMessageFor(m => m.ScheduledDate)
</div>
<input type="submit" value="Get Report" />
}
With this in place, you should be able to post the data in the initial page using ajax. Then based on the response received you will open another window\tab (as mentioned, depending on browser and user settings this may be opened in a new window or even be blocked) with the second page content (OrderListItems).
Here's a skeleton of what I think you are trying to do. Note that window.open is a popup though and most user will have popups blocked.
<form id="formCreateOrderListReport">
<input type="text" vaule="testing" name="id" id="id"/>
<input type="submit" value="submit" />
</form>
<script type="text/javascript">
$('#formCreateOrderListReport').on('submit', function (event) {
$.ajax({
type: "POST",
url: '/home/test',
data: { id: $('#id').val()},
cache: false
}).done(function () {
debugger;
alert("success");
var newUrl = '/home/contact';
window.open(newUrl, '_blank');
}).fail(function () {
debugger;
alert("error");
});
return false;
});
</script>
Scale down the app to get the UI flow that you want then work with data.
It is easy to submit form to an action method in the controller which has strongly typed textboxes for example, with a submit button, but what if I want to send the exact same form with the strongly typed textboxes through jquery perhaps the $.ajax call after something else has been clicked.
code like this:
#Html.TextBoxFor(m => m.topTenFav.YoutubeLink,new { id="youTubeLinkTxt"})
does all the work for us and it's very simple to map the properties of our object in the controller
[HttpPost]
public ActionResult AddTopTenFav(HomeViewModel topTen)
{
topTen.topTenFav.Date = DateTime.Now;
topTen.topTenFav.UserName = User.Identity.Name;
repository.AddTopTen(topTen);
repository.Save();
return RedirectToAction("Index");
}
How would I send this form to the controller, map the textboxes in the form to object's properties on a click event such as
$("#btnAddGenre").click(function () {}
#using (Html.BeginForm(
"AddTopTenFav", "Home", FormMethod.Post, new { id = "AddTopTenFavForm" }))
{
<span id="youTubeLinkSpan">Youtube Link</span>
<div>
#Html.TextBoxFor(m => m.topTenFav.YoutubeLink,new { id="youTubeLinkTxt"})
</div>
<span id="youTubeNameSpan">Song Title</span>
<div>
#Html.TextBoxFor(m => m.topTenFav.Title,new { id="youTubeNameTxt"})
</div>
<button type="submit" name="btnSubmit" value="">submit</button>
}
You can do the following post:
$(document).ready(function(){
$('#btnAddGenre').click(function () {
$.post(
$('#AddTopTenFavForm').attr('action'),
$('#AddTopTenFavForm').serialize,
function (data) {
window.location = #Url.Action("Index");
},
'html' // returned data type
);
});
});
I use the html data type so you can return whatever you want and the redirect occurs on the window.location using the #Url.Action to give the location.
Please if it work mark as accepted answer
yes you can post the data of strongly typed textboxex using jquery.
First you have to do
take the values of all the textboxex in jquery using the below code.
var xx= $("#xx").val();
this will give the val in xx from your mvc text box.
Then by using jquery ajax call you can call the action method.
the code is below.
$.get("/XXXX/YY/1", { xxName: xx }, function (data) {
var status = data;
alert(status);
if (status) {
return true;
}
else {
alert("The book with this name is already present. TRY DIFFERENT NAME!")
return false;
}
});
here xxxx is controller amd yy is action method name.the next parameter is the value of all the textboxes which you want to send as an parameter.
This will perform the ajax call and return the value.
Please tell me if you find any problem the i will give the whole code.
So I followed the example in the Dojo - Using the Dojo JavaScript Library to Build Ajax Applications to add server-side validation to the username validationtextbox field on my form. Basically I added a usernameOnChange function that submitted an xhrGet request, the xhrGet returns JSON and is handled by the usernameValidationHandler.
It works great, but the usernameValidationHandler only sets the tooltip display message to an error. It doesn't set the field to be invalid and thus the user can still submit the form. How do I set the field to be invalid so the form won't submit?
<input type="text" id="userName" name="userName" size="20"
dojoType="dijit.form.ValidationTextBox"
trim="true"
required="true"
onChange="userNameOnChange"
regExp="\w+"
invalidMessage="User name is required"
/>
function userNameOnChange() {
var userName = dijit.byId("userName").getValue();
if (userName == "") {
return;
}
dojo.xhrGet( {
url: "validateUserName.jsp?userName=" + userName,
handleAs: "json",
handle: userNameValidationHandler
});
}
function userNameValidationHandler(response) {
dijit.byId("userName").displayMessage();
if (!response.valid) {
var errorMessage = "User name already taken";
// Display error message as tooltip next to field
dijit.byId("userName").displayMessage(errorMessage);
// HOW DO I SET THE FIELD TO BE INVALID NOW???
}
}
It seems I was having the same issues when I used the validation method (validator) for the control. I think the issue is with the nature of the xhrGet method as it is asychronous, so the method for determining if value is valid returns before the query is complete. Anyways, this is what I did to get it working. If there is another way, hopefully someone can post.
dojo.require("dijit.form.ValidationTextBox");
function validateUsername(value, constraint) {
// I believe the whole reason you have to hack at control to get it to
// display an error is due to the nature of the xhrGet call. Since the
// call is being made asychronously, the method would have already
// returned a result to the html control before query has finished.
// Therefore you have to do the extra method calls below. Also note
// that when the form goes for submission, it calls each controls validator
// method again! Meaning it will query the webpage again.
var loginID = dijit.byId("user_login");
var bNoNameFound = ("Error" == loginID.get("state")) ? false : true;
if ("" == loginID.value) {
// for some required=true is not kicking in, so we are forcing it.
bNoNameFound = false;
} else {
if (false == loginID._focused) {
console.log("Checking username...");
dojo.xhrGet({
url: "functions/does_user_exist.php?user_login=" + value,
handleAs: 'text',
content: {
l: value
},
timeout: 10000,
load: function(data) {
if (1 == data) {
// setting the state to error since the username is already taken
bNoNameFound = false;
loginID.set("state", "Error");
loginID.displayMessage("The username is already taken...");
// used to change the style of the control to represent a error
loginID._setStateClass();
console.log("Invalid username");
} else {
bNoNameFound = true;
loginID.set("state", "");
loginID.displayMessage("");
}
}
});
}
}
return bNoNameFound;
}
<input dojoType="dijit.form.ValidationTextBox" type="text" name="user_login" id="user_login" value="" minSize="1" maxSize="25" tabindex="10" required="true" trim="true" regExp="\w+" validator=validateUsername />
Note: I also tried using "sync" in the xhrGet parameters as well. It also had issues (aside from the obvious of locking the control until query is done)...
You could subclass the widget to override the validator method. Perhaps chain up, if you want the base functionality, then, if the result is true, run your own test with the getXhr and return the result.
An example at dojocampus just clobbers the validator method. That might also work, depending on what you want to do.