PDA

View Full Version : AJAX POST Failing



bluewalrus
09-17-2010, 04:19 PM
I've used the GET xmlhttp request before but can't seem to get the post one to work for me. Can anyone see what I'm doing wrong?


<html>
<head>
<script type="text/javascript">
function saveTitle()
{
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
alert(xmlhttp.responseText);
}
}
var title = "title=" + document.getElementById("title").value;
xmlhttp.open("POST","saveTitle.php",true);
xmlhttp.send(title);
}
</script>
</head>
<body>
<input name="title" id="title" onblur="saveTitle()" type="text" />
</body>
</html>

saveTitle.php has



<?php
echo $_POST['title'];
?>


Firebug shows the POST data as title=asdf but the alert coming back from the response so I think I'm calling that wrong, or the value is not being set to title as I think it is...

jscheuer1
09-17-2010, 04:57 PM
That's not how you send POST data. And honestly I don't see why you cannot send this as a GET, it would be simpler. But if you must use POST or want to learn (it can be required if there's tons of data, and perhaps in other situations), this page describes the differences needed fairly well:

http://www.openjs.com/articles/ajax_xmlhttp_using_post.php

As shown there, you need to send() the data (as opposed to null) after setting up the appropriate headers. No query string need be used with the URL, and in fact will be ignored if it is, unless perhaps if the page fetched parses its GET data.

Alternatively, and I would recommend this for its flexibility and completeness, as well as for how it can simplify requests, using the jQuery 1.4.2 built in ajax() function. It can take a little getting used to. Once you familiarize yourself with it it's so simple as all the headers, branching and much of the parsing (in the case of a true xml response) are taken care of. And you get the added benefit of being able to use jQuery to implement/manipulate the response. See:

http://api.jquery.com/jQuery.ajax/

One important thing to bear in mind though is that some servers are not configured to allow AJAX POST requests. Almost all will do GETs.

bluewalrus
09-20-2010, 04:21 PM
The requests may be too long to send as get requests and I don't want people to be able to trigger events on the page via the address bar.

jscheuer1
09-21-2010, 01:08 AM
Right, that's the one reason I mentioned (tons of data), and one of the reasons I alluded to when I said "perhaps other reasons" (in your case - prevent users easy access to the page from the address bar).

Even with POST, a user can gain the same sort of control they can with GET. But, instead of using the address bar, they have to make up a form to do it.

bluewalrus
09-21-2010, 01:21 AM
Yea, I'm going to look into only accepting forms from my domain/ servers IP address later, this is still in development right now so I got some time.

I have this currently but is there a way to make it if not equal to?




var regex = new RegExp('^.*?@.*?\..*');
var email = document.getElementById("auth_email").value;
if (email.match(regex)) {


The ! operator cant be used in javascript like in can in PHP, or can it?



$regex = new RegExp('^.*?@.*?\..*');
$email = $_POST['email'];
if (!preg_match($regex, $email)) {

jscheuer1
09-21-2010, 02:32 AM
Sure. But the RegExp() constructor is expensive, cumbersome, and generally only required when the exact value of the regex must be composed from variables.

Expensive because it's a constructor. One should always use a literal if possible:


var ar = [];

not:


var ar = new Array();


var str = '';

not:


var str = new String();

Cumbersome because a constructor is always typed as an Object, which can get confusing if you later want to find out what you have via the typeof check (string, object, number, function, etc.). And in this case because, like eval(), it takes as its main argument a string. That means for example that, where you have:



new RegExp('^.*?@.*?\..*');

The highlighted part will be escaped as it is in a string, so becomes a dot, meaning any character, when your intended meaning is a literal dot. I think that in order to get the intended meaning it has to be \\. or even \\\.

Since you know what the regex is ahead of time, you can do:


var regex = /^.*?@.*?\..*/;

Which is totally unambiguous, and more efficient for the script parser.

In an unrelated matter, when you do:


if (email.match(regex)) {

If you don't need the matches, this is more efficient:


if (regex.test(email)) {

With match() it would be null if there's no match, with test(), false. So either way the ! (literally not) operator should work, provided the regex is correct, ex:


if (!regex.test(email)) {

With test, which returns only true or false, things are clearer.

Whenever I have a problem in a case like this I set the string to be evaluated (email in this case) to something I think I know what the result should be, and use an alert to check:


var regex = /^.*?@.*?\..*/;
var email = 'someone@some.com';
alert(regex.test(email));

I can keep changing the value of email to test different possibilities. I can also easily change the regex to fine tune it.

bluewalrus
09-27-2010, 04:02 AM
I've returned to this with another question more a general JS question but since I'm using it with this function I thought I'd keep it here. My question is how can I focus on a text field (the email one) if the email address is entered incorrectly. I currently have


var regex = /^.*?@.*?\..*/;
var email = document.getElementById("auth_email").value;
if (!regex.test(email)) {
return alert("Please enter a valid email address.");
}

I've tried adding the following to line 4 there but it doesn't seem to work. I think my syntax is off.



return alert("Please enter a valid email address."), document.getElementById("auth_email").focus;

jscheuer1
09-27-2010, 05:49 AM
Once you return anything, the function is over. Nothing else after that gets processed. It's sort of like break in a loop, only for the entire function.

And here:


document.getElementById("auth_email").focus;

That doesn't do anything. It's not an error though, just a statement. To execute it you need the () at the end:


document.getElementById("auth_email").focus();

Having an alert commands focus, so you cannot set focus on anything before it without losing that focus when the alert fires. Your current code doesn't suffer from that, but an attempt at a quick fix might result in such a situation.

The code you show doesn't appear to be a function. It must be a function though, otherwise you would be getting an error on having a return outside a function.

Returning an alert isn't necessary. It will fire anyway. You only need to return to get out of the function and to optionally at the same time pass a value from the function to another function that called it. A function that would end anyway doesn't need a return. I'm guessing you need the return there to prevent further processing. So, taking all of this into account:


var regex = /^.*?@.*?\..*/;
var email = document.getElementById("auth_email").value;
if (!regex.test(email)) {
alert("Please enter a valid email address.");
document.getElementById("auth_email").focus();
return;
}

Note: Your variables probably could be declared earlier, outside the function. But shouldn't be in the global scope. This speeds processing because each time the function runs, it doesn't have to figure out what's what. This can be tricky though. With an element you cannot declare it as a variable until it has been parsed. There's not enough of the code there in your post to show the specifics of how this could be done in this case.

bluewalrus
09-27-2010, 03:43 PM
Oh, thanks. That explains a bit more, yes this is enclosed in a function just figured I'd post the minimum amount of code though. So the focus looks like it only focus the text feature of the browser but not the view field, if that makes sense. Is there a way to also focus the "view" field?

jscheuer1
09-27-2010, 04:28 PM
I'm not sure what you mean by:


So the focus looks like it only focus the text feature of the browser but not the view field

The focus() method technically only applies to form elements and links and only if their style, type (in the case of a form element) and attributes permit focus. IE and Firefox (perhaps other mozilla) also apply it to window, which should include frames and iframes, which are also windows. However, this is non-standard. All others I'm aware of will ignore attempts to focus on a window, no error, just nothing happens. Also, even in Firefox and IE, focusing on the window doesn't always mean what you might think.

bluewalrus
09-27-2010, 07:12 PM
Well the alert bounces the scroll bar to the top, once dismissed the window closes but the scroll bar doesn't go back to where it was/ where the focus is. The blinking cursor though is there if the user uses the mouse to scroll down and see.

jscheuer1
09-27-2010, 10:29 PM
I could be wrong. Offhand though I'd say that's a little unusual. An alert on a page, as far as I know, typically doesn't affect the scroll state of the window.

I'm flying blind here without the full markup and script code. I'm thinking too, knowing you, that there could be PHP involved as well. In any case, if the form submits to the page it's on (what all forms do if there's no action attribute specified for the form), it will appear to scroll to the top. If the form doesn't need to submit, we can prevent that by making the return value false for the submit event. This can be done always, or as conditional upon what your onsubmit function returns, example:


<form onsubmit="return checkEmail();">


function checkEmail(){
if(email is OK){
return true;
}
return false;
}

The green stuff is pseudo code, substitute your own actual code there or work off of the concept in some other way.

What happens is if the email is OK, the form submits, otherwise not.

To have it always not submit:


<form onsubmit="checkEmail(); return false;">

This all assumes javascript is enabled. Without javascript, the form will always submit unless perhaps you do something like so:


<form action="javascript:void(0);" onsubmit="return checkEmail();">

Then it should never submit with javascript disabled, and only submit with javascript if the checkEmail function returns true.

If you want more help on the behavior of that alert, give me the full code and markup or a link to the page. You may PM me if you don't want it in the open forum.

jscheuer1
09-28-2010, 01:02 AM
OK, I got the link in a PM. But I can't seem to get it to alert anything, what do I need to do (step by step) for it to alert "Please enter a valid email address."? Also, even if I could do that, the page seems far too short to require a vertical scrollbar anyway, so where does that come into play? I'm guessing perhaps after I've added a number of entries. If so, again - how do I do that, how do I add entries?

bluewalrus
09-28-2010, 01:05 AM
Oh, sorry I knew i forgot something, click the new author button. Then the form should expand, enter an incorrect email address or just click save author and it should do it.

jscheuer1
09-28-2010, 01:55 AM
Partly my fault, I had javascript temporarily disabled for testing something else and forgot to turn it back on. I probably could have figured it out if not for that.

OK, here's the 'button' (actually a link) that gets things rolling:


<a href="#" onclick="ajax(request = 3)">Save Author</a>

Any anchor link tag (any a tag with an href attribute) will fire when clicked unless something is done to prevent that. That's what's happening, the function runs, but the link also fires, bringing the page to the top, after first firing the alert. Without precisely tracing all of what the ajax function does, it seems fairly certain that it doesn't require this link or either of the other two links that use it (which are the only other calls to it that I see) to fire. This is sort of like the situation I was describing with a form and its action attribute, only - with an a tag, there's no default href if it is omitted, and there are other considerations.

To make (in an effort to explain things) what has already become a bit longer of a story than perhaps it needed to be longer:


<a href="javascript:ajax(request = 3);" onclick="ajax(request = 3); return false;">Save Author</a>

The key here is returning false on the onclick. The href then becomes a 'throw away', it will never fire. But it will appear in the status bar on hover of the link, giving the user a clue as to what will happen if clicked.

The logic is a bit convoluted, it could be just:


<a href="javascript:ajax(request = 3);">Save Author</a>

and that would work in most cases, but can have problems in some browsers. Or:


<a href="#" onclick="ajax(request = 3); return false;">Save Author</a>

Totally acceptable, but no clue for the user on hover. In fact, the href could be removed entirely (but then style would need to be added to get the pointer cursor) or changed to something more descriptive like:


<a href="javascript:saveAuthor();" onclick="ajax(request = 3); return false;">Save Author</a>

Like I said, with the return false on the onclick, even though the href would now cause an error in javascript, it will never fire, so it's OK. This last is perhaps the best way to do it in this case.

bluewalrus
09-28-2010, 02:16 AM
That did it. Thanks.