I have a main.php page with multiple divs. I load whole pages in these divs using AJAX. Some of these pages have forms with submit buttons. The structure of the pages is like so:

For acc_settings.php

<form enctype="multipart/form-data" method="post" action="acc_settings.php"  >
.
.
<button type='submit' name='update' >UPDATE</button>
</form>

So the form is processed by acc_settings.php itself. When the submit button is pressed, the form info is sent to acc_settings but the browser loads up acc_settings.php

What I want is that the form should remain the way it is but the response should be displayed in the same div in main.php and acc_settings.php should not be opened by the browser.

There might be an AJAX solution to this.

You need to call an ajax function not the submit form action - then target the div you wish to display back too
[sorry for quick reply]

You need to call an ajax function not the submit form action - then target the div you wish to display back too
[sorry for quick reply]

I know but how? :)

I mean how do I call an AJAX function instead of the form submit?Please keep in mind that there are many such buttons and a solution which can be applied to all without many changes would be good.

psyb0rg,

Ajax is indeed the way to go.

First some javascript:

function createRequestObject(){
   if(window.XMLHttpRequest) {
      return new XMLHttpRequest(); // IE 7, Firefox, Safari, Opera...
   }
   else if(window.ActiveXObject) {
      return new ActiveXObject("Microsoft.XMLHTTP"); // Internet Explorer 6, 5
   }
   else { alert('Problem creating the XMLHttpRequest object'); }
   return false;
}

function ajaxFormSubmit(form){
	var params = getParams(form);
	var action = form.getAttribute('action');
	var httpRequest = createRequestObject();
	if(!httpRequest) return false;
	httpRequest.onreadystatechange = function() {
		if(httpRequest.readyState == 4) {
			//Here do whatever you need to with the response (httpRequest.responseText)
			//document.getElementByid('myDiv').innerHTML = httpRequest.responseText;//for example
		}
	}
	httpRequest.open('POST', action, true);
	httpRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	//httpRequest.setRequestHeader("Content-type", "multipart/form-data");//Possible alternative?
	httpRequest.setRequestHeader("Content-length", params.length);
	httpRequest.setRequestHeader("Connection", "close");
	httpRequest.send(params);
	return false;
}
function getParams(form) {
	var params = [];
	for (i=0; i<form.elements.length; i++){
		var e = form.elements[i];
		var n = e.getAttribute('name');
		if (!n) continue;
		if (e.tagName == "INPUT"){
			switch (e.getAttribute('type')){
				case "text":
					params.push(n + "=" + URLEncode(e.value));
				break;
				case "checkbox":
					if (e.checked) { params.push(n + "=" + URLEncode(e.value)); }
					else { params.push(n + "="); }
				break;
				case "radio":
					if (e.checked) { params.push(n + "=" + URLEncode(e.value)); }
				break;
			}
		}
		if (e.tagName == "TEXTAREA"){
			params.push(n + "=" + URLEncode(e.value));
		}
		if (e.tagName == "SELECT"){
			params.push(n + "=" + URLEncode(e.options[e.selectedIndex].value));
		}
	}
	return '?' + params.join('&');
}
function URLEncode(clearString){
	// Encode strings to be compatible with php's urldecode().
	// Based on "Javascript URL encoding and decoding", http://cass-hacks.com/articles/code/js_url_encode_decode/
	if(!Number.toString) { return clearString; }//Very old browsers
	var output = [];
	var x = 0;
	clearString = clearString.toString();
	var regex = /(^[a-zA-Z0-9_.]*)/;
	while (x < clearString.length) {
		var match = regex.exec(clearString.substr(x));
		if (match != null && match.length > 1 && match[1] != '') {
			output.push(match[1]);
			x += match[1].length;
		}
		else {
			if (clearString.substr(x,1) == ' '){ output.push('+'); }
			else {
				var charCode = clearString.charCodeAt(x);
				var hexVal = charCode.toString(16);
				output.push('%' + ( hexVal.length < 2 ? '0' : '' ) + hexVal.toUpperCase());
			}
			x++;
	    }
	}
	return output.join('');
}

Now a mod to your HTML:

<form enctype="multipart/form-data" method="post" action="acc_settings.php" onsubmit="return ajaxFormSubmit(this);">
.
.
<button type='submit' name='update' >UPDATE</button>
</form>

Changes should be easy, because you just have to add onsubmit="....." to each of your form tags.

I've only done some rudimentary testing not involving PHP so please foregive slips and plese test thoroughly yourself.

Airshow

Thanks for the reply Airshow. It worked.

One correction, line 23 should be

httpRequest.open('POST', action [B]+ params[/B], true);

That's great psyb0rg.

I'm a bit puzzled about that correction though because the line httpRequest.send(params); is supposed to look after the params for the "POST" method. Tacking onto the url is the "GET" way to do it. Maybe try httpRequest.send(null); and see if it still works.

Server-side, do you pick up the parameters in $_GET or $_POST?

Another thing to try: revert to my code but change the line return '?' + params.join('&'); to return params.join('&'); . It may be that the leading ? was messsing up the POST.

Airshow

@Airshow, yes you're right. I changed back the changes.

There is one more problem. How do I capture the button that was clicked. The getParams() function gets values of ALL the elements on a form including all the buttons, but I also need the button which was pressed by the user as I have multiple buttons per page, for example NEXT and PREVIOUS buttons.

@Airshow, yes you were right. Made the changes.

One more problem. How do I know which button was pressed in the form? I need the information in getParams(), which right now gets ALL the controls in a form. I have many buttons in my forms and need to know which was actually pressed.
Thanks

psybOrg,

This is slightly tricky as there's no naturally occurring button property to test, to see which submit button was clicked. For a normal (non-AJAX) form submission it's easy because HTML does the hard work and you can test server-side.

The only solution I can think of for this AJAX-POST is to establish an onclick event handler for each submit button. From that point, there must be a million ways to proceed - I have chosen to tuck away the value of the clicked button in a contrived form attribute "s", which can then be read in the getParams function.

In my javascript :

//-- Find
	return params.join('&');
//--Insert before
	params.push("submit=" + URLEncode(form.getAttribute('s')));

In my HTML, replace the submit button with :

<input type="submit" value="UPDATE" onclick="this.form.setAttribute('s', this.value);">
	<input type="submit" value="OTHER_1" onclick="this.form.setAttribute('s', this.value);">
	<input type="submit" value="OTHER_2" onclick="this.form.setAttribute('s', this.value);">

That will add "&submit=UPDATE" (or "OTHER_1" etc.) to the params list, so server-side you can test $_POST to see which submit button was clicked.

Client-side tested in IE6, FF 3.0.13 and Opera 9.01.

I have wracked my brain to think of a reason it might not be reliable but can't think of one.

Good luck with it.

Airshow

Thanks for the reply.
I used a similar solution. For the form:

onSubmit='return ajaxFormSubmit(this, window.clicked)

and

onclick="window.clicked=this.value;"

for every button.

I sent the button as an argument because that allows me to use it other places as well.

Thanks!

This article has been dead for over six months. Start a new discussion instead.