Populate field according to another field with AJAX

quantum_leap 11 Jul, 2012
I have a MySQL table that contains sup_number and site fields amongst others. In my form I would like the user to enter the SUP number. That number will then get validated while the user is typing and populate another field next to it with the current site that this sup number is related to. The sup number must be a 6 digit number. I've already entered two sup numbers in the sup_number field to test.

It seems to me that I need to use AJAX in this case. I tried to follow the code example found on Chapter 12: Adding Advanced Features - Using Ajax to look up e-mail addresses in the Chronoforms for Joomla site Cookbook. So I copied all code to just make that work and then take it from there. The example should look up emails from the jos_users table and on focus out turn the input box green if the email exists or turn the input box red if the email doesn't exist. Here is the code taken from the book.
Form HTML box:
window.addEvent('domready', function() {
	// set the url to send the request to
	var url = 'index.php?option=com_chronocontact&chronoformname=Email_Lookup&task=extra&format=raw';
	var email = $('email');
	email.addEvent('blur', function() {
    	// clear any background color from the input
    	email.setStyle('background-color', 'white');
        // check that the email address is valid
        regex = /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i;
        var value = email.value.trim();
        if ( value.length > 6 && regex.test(value) ) {
            // if all is well send the JSON request
            var jSonRequest = new Json.Remote(url, {
            	onComplete: function(r) {
                	// check the result and set the background color
                  	if ( r.email_ok ) {
                    	email.setStyle('background-color', 'green');
                  	} else {
                    	email.setStyle('background-color', 'red');
                  	}
                }
            }).send({'email': email.value});
        } else {
          	// if this isn't a valid email set background color red
          	email.setStyle('background-color', 'red');
        }
    });
});


Form JavaScript code:
window.addEvent('domready', function() {
	// set the url to send the request to
	var url = 'index.php?option=com_chronocontact&chronoformname=Email_Lookup&task=extra&format=raw';
	var email = $('email');
	email.addEvent('blur', function() {
    	// clear any background color from the input
    	email.setStyle('background-color', 'white');
        // check that the email address is valid
        regex = /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i;
        var value = email.value.trim();
        if ( value.length > 6 && regex.test(value) ) {
            // if all is well send the JSON request
            var jSonRequest = new Json.Remote(url, {
            	onComplete: function(r) {
                	// check the result and set the background color
                  	if ( r.email_ok ) {
                    	email.setStyle('background-color', 'green');
                  	} else {
                    	email.setStyle('background-color', 'red');
                  	}
                }
            }).send({'email': email.value});
        } else {
          	// if this isn't a valid email set background color red
          	email.setStyle('background-color', 'red');
        }
    });
});


Extra code 1:
<?php
// Code for Extra Code
// clean up the JSON message
$json = stripslashes($_POST['json']);
$json = json_decode($json);
$email = strtolower(trim($json->email));
// check that the email field isn't empty
$response = false;
if ( $email ) {
	// Check the database
	$db =& JFactory::getDBO();
	$query = "
		SELECT COUNT(*)
			FROM `#__users`
			WHERE LOWER(`email`) = ".$db->quote($email).";
	";
	$db->setQuery($query);
	$response = (bool) !$db->loadResult();
}
$response = array('email_ok' => $response );
//send the reply
echo json_encode($response);
// stop the from running
$MyForm->stopRunning = true;
die;
?>


Now the example here works BUT when the email exists it turns the input box to RED and when it's non existent it turns the box to GREEN! Why is that happening instead of the other way round? Also how could I modify the script to fit what I want to do?
quantum_leap 11 Jul, 2012
I just modified the bit of code in the Extra Code 1 box from
$response = (bool) !$db->loadResult();
to
$response = (bool) $db->loadResult();
(took the "!" out) and it turns green when the email is found, which is good. I was wondering how I could modify the code to solve my problem now...
GreyHead 11 Jul, 2012
Hi quantum_leap ,

I think you need to amend the extra code to return the six digit number if one is found or an empty string if not and then alter the onComplete function in the JavaScript to set the value of the input using the result.

Bob
quantum_leap 11 Jul, 2012
Hi. Assuming that I still want to keep the functionality of turning the sup_number field color green or red according to the value entered. I've modified the code accordingly and added an
var site = $('site');
variable in the javascript area.

The code is:

HTML:
<div class="form_item">
    <div class="form_element cf_textbox">
        <label class="cf_label" style="width: 150px;">SUP Number</label>
        <input class="cf_inputbox" maxlength="150" size="30" title="" id="sup_number" name="sup_number" type="text" />
    </div>
    <div class="cfclear"> </div>
</div>

<div class="form_item">
    <div class="form_element cf_textbox">
        <label class="cf_label" style="width: 150px;">Site</label>
        <input class="cf_inputbox" maxlength="150" size="30" title="" id="site" name="site" value="" type="text" />
    </div>
    <div class="cfclear"> </div>
</div>


Javascript:
window.addEvent('domready', function() {
	// set the url to send the request to
	var url = 'index.php?option=com_chronocontact&chronoformname=SUP_Lookup&task=extra&format=raw';
	var sup_number = $('sup_number');
        var site = $('site');
	sup_number.addEvent('blur', function() {
    	// clear any background color from the input
    	sup_number.setStyle('background-color', 'white');
        // check that the email address is valid
        if (sup_number.length = 6 ) {
            // if all is well send the JSON request
            var jSonRequest = new Json.Remote(url, {
            	onComplete: function(r) {
                	// check the result and set the background color
                  	if ( r.sup_number_ok ) {
                    	sup_number.setStyle('background-color', 'green');
                  	} else {
                    	sup_number.setStyle('background-color', 'red');
                  	}
                }
            }).send({'sup_number': sup_number.value});
        } else {
          	// if this isn't a valid sup number set background color red
          	sup_number.setStyle('background-color', 'red');
        }
    });
});


Extra code box:
<?php
// Code for Extra Code
// clean up the JSON message
$json = stripslashes($_POST['json']);
$json = json_decode($json);
$sup_number = $json->sup_number;
// check that the sup number field isn't empty
$response = false;
if ( $sup_number ) {
	// Check the database
	$db =& JFactory::getDBO();
	$query = "
		SELECT COUNT(*)
			FROM `_jos_installations`
			WHERE `sup_number` = ".$db->quote($sup_number).";
	";
	$db->setQuery($query);
	$response = (bool) $db->loadResult();
}
$response = array('sup_number_ok' => $response );
//send the reply
echo json_encode($response);
// stop the from running
//$MyForm->stopRunning = true;
//die;
?>


The color validation works fine but I have no idea how I can populate the site field depended on the value of the sup_number. It's really difficult for me to understand, could you maybe provide an example? It's just a case of matching the sup_number field with the site field but I have no idea how to do it!
quantum_leap 12 Jul, 2012
I know I can set the value of site in the javascript area by referencing
$('site').value
but I don't know what value should that be. Obviously it will have to come from the PHP extra box so all I am asking is the query that would create a variable so I could then assign in the javascript box. The problem is that when I set a simple variable in the php box
$response2 == "test"
and then doing a
$('site').value = response2;
in the javascript box, nothing is coming back from php. Pretty desperate here...
quantum_leap 13 Jul, 2012
Took me 3 days of continous digging and searching to pin it down.

Form HTML::
<div class="form_item">
    <div class="form_element cf_textbox">
        <label class="cf_label" style="width: 150px;">SUP Number</label>
        <input class="cf_inputbox" maxlength="150" size="30" title="" id="sup_number" name="sup_number" type="text" />
    </div>
    <div class="cfclear"> </div>
</div>

<div class="form_item">
    <div class="form_element cf_textbox">
        <label class="cf_label" style="width: 150px;">Site</label>
        <input class="cf_inputbox" maxlength="150" size="30" title="" id="site" name="site" value="" type="text" />
    </div>
    <div class="cfclear"> </div>
</div>


Form JavaScript:
window.addEvent('domready', function() {
	// set the url to send the request to
	var url = 'index.php?option=com_chronocontact&chronoformname=Installations&task=extra&format=raw';
	var sup_number = $('sup_number');
        var site = $('site');
	sup_number.addEvent('blur', function() {
    	// clear any background color from the input
    	sup_number.setStyle('background-color', 'white');
        // check that the email address is valid
        if (sup_number.length = 6 ) {
            // if all is well send the JSON request
            var jSonRequest = new Json.Remote(url, {
            	onComplete: function(r) {
                	// check the result and set the background color
                  	if ( r.sup_number_ok ) {
                    	sup_number.setStyle('background-color', '#66cc99');
                        site.value = r.sup_number_ok;
                  	} else {
                    	sup_number.setStyle('background-color', 'red');
                        site.value = "No site associated with that SUP number";
                  	}
                }
            }).send({'sup_number': sup_number.value});
        } else {
          	// if this isn't a valid sup number set background color red
          	sup_number.setStyle('background-color', 'red');
                site.value = "No site associated with that SUP number";
        }
    });
});


Extra code 1:
<?php
// Code for Extra Code
// clean up the JSON message
$json = stripslashes($_POST['json']);
$json = json_decode($json);
$sup_number = $json->sup_number;
// check that the sup number field isn't empty
$response = false;
if ( $sup_number ) {
	// Check the database
	$db =& JFactory::getDBO();
	$query = "
		SELECT `site`
			FROM `_jos_sup`
			WHERE `sup_number` = ".$db->quote($sup_number).";
	";
	$db->setQuery($query);
	$response = $db->loadResult();
}
$response = array('sup_number_ok' => $response );

//send the reply
echo json_encode($response);

// stop the form running
//$MyForm->stopRunning = true;
//die;
?>
GreyHead 13 Jul, 2012
Hi quantum_leap,

I'm not quite sure what you are returning. Browser web developer tools are invaluable in letting you look at the actual values.

In the code I posted r is the JSON value returned so if you had sup_number in the array then I'd expect you to use
$('site').value = r.sup_number;


But . . . your Extra code 1 box appears to be using JavaScript instead of PHP so I don't think it will do anything. Maybe you posted the wrong code block there?

Bob
quantum_leap 13 Jul, 2012
Sorry you are right, I've just updated the code!

But i've also noticed that the behaviour only works in Firefox and Opera and NOT in IE, Chrome and Safari...
quantum_leap 13 Jul, 2012
I've just noticed that the javascript code I am importing for the hideable inputs(found in the Chronoforms book) clashes with the javascript being used for the ajax functionality. It only works in Firefox and Opera. Is there a way I could make them work together?
GreyHead 14 Jul, 2012
Hi quantum_leap,

There shouldn't be a clash between them unless the same variable is being re-defined. What error messages do you see in the JavaScript console?

Bob
quantum_leap 17 Jul, 2012
Hi Bob. The error message is

SCRIPT5007: Unable to get value of the property 'addEvent': object is null or undefined
index.php?option=com_chronocontact&chronoformname=Installations, line 115 character 2

quantum_leap 18 Jul, 2012
Whenever I remove the usable_forms.js script which I've imported, it works fine but obviously I don't get hideable inputs functionality. The code is this:
/*****************************************/
/** Usable Forms 2.0, November 2005     **/
/** Written by ppk, www.quirksmode.org  **/
/** Instructions for use on my site     **/
/**                                     **/
/** You may use or change this script   **/
/** only when this copyright notice     **/
/** is intact.                          **/
/**                                     **/
/** If you extend the script, please    **/
/** add a short description and your    **/
/** name below.                         **/
/*****************************************/


var containerTag = 'DIV';

var compatible = (
	document.getElementById && document.getElementsByTagName && document.createElement
	&&
	!(navigator.userAgent.indexOf('MSIE 5') != -1 && navigator.userAgent.indexOf('Mac') != -1)
	);

if (compatible) {
	document.write('<style>.accessibility{display: none}</style>');
	var waitingRoom = document.createElement('div');
}

var hiddenFormFieldsPointers = new Object();


function prepareForm()
{
	if (!compatible) return;
	var marker = document.createElement(containerTag);
	marker.style.display = 'none';

	var x = document.getElementsByTagName('select');
	for (var i=0;i<x.length;i++)
		addEventUF(x[i],'change',showHideFields)

	var x = document.getElementsByTagName(containerTag);
	var hiddenFields = new Array;
	for (var i=0;i<x.length;i++)
	{
		if (x[i].getAttribute('rel'))
		{
			var y = getAllFormFields(x[i]);
			x[i].nestedRels = new Array();
			for (var j=0;j<y.length;j++)
			{
				var rel = y[j].getAttribute('rel');
				if (!rel || rel == 'none') continue;
				x[i].nestedRels.push(rel);
			}
			if (!x[i].nestedRels.length) x[i].nestedRels = null;
			hiddenFields.push(x[i]);
		}
	}

	while (hiddenFields.length)
	{
		var rel = hiddenFields[0].getAttribute('rel');
		if (!hiddenFormFieldsPointers[rel])
			hiddenFormFieldsPointers[rel] = new Array();
		var relIndex = hiddenFormFieldsPointers[rel].length;
		hiddenFormFieldsPointers[rel][relIndex] = hiddenFields[0];
		var newMarker = marker.cloneNode(true);
		newMarker.id = rel + relIndex;
		hiddenFields[0].parentNode.replaceChild(newMarker,hiddenFields[0]);
		waitingRoom.appendChild(hiddenFields.shift());
	}
	
	setDefaults();
	addEventUF(document,'click',showHideFields);
}

function setDefaults()
{
	var y = document.getElementsByTagName('input');
	for (var i=0;i<y.length;i++)
	{
		if (y[i].checked && y[i].getAttribute('rel'))
			intoMainForm(y[i].getAttribute('rel'))
	}

	var z = document.getElementsByTagName('select');
	for (var i=0;i<z.length;i++)
	{
		if (z[i].options[z[i].selectedIndex].getAttribute('rel'))
			intoMainForm(z[i].options[z[i].selectedIndex].getAttribute('rel'))
	}

}

function showHideFields(e)
{
	if (!e) var e = window.event;
	var tg = e.target || e.srcElement;

	if (tg.nodeName == 'LABEL')
	{
		var relatedFieldName = tg.getAttribute('for') || tg.getAttribute('htmlFor');
		tg = document.getElementById(relatedFieldName);
	}
		
	if (
		!(tg.nodeName == 'SELECT' && e.type == 'change')
		&&
		!(tg.nodeName == 'INPUT' && tg.getAttribute('rel'))
	   ) return;

	var fieldsToBeInserted = tg.getAttribute('rel');

	if (tg.type == 'checkbox')
	{
		if (tg.checked)
			intoMainForm(fieldsToBeInserted);
		else
			intoWaitingRoom(fieldsToBeInserted);
	}
	else if (tg.type == 'radio')
	{
		removeOthers(tg.form[tg.name],fieldsToBeInserted)
		intoMainForm(fieldsToBeInserted);
	}
	else if (tg.type == 'select-one')
	{
		fieldsToBeInserted = tg.options[tg.selectedIndex].getAttribute('rel');
		removeOthers(tg.options,fieldsToBeInserted);
		intoMainForm(fieldsToBeInserted);
	}
}

function removeOthers(others,fieldsToBeInserted)
{
	for (var i=0;i<others.length;i++)
	{
		var show = others[i].getAttribute('rel');
		if (show == fieldsToBeInserted) continue;
		intoWaitingRoom(show);
	}
}

function intoWaitingRoom(relation)
{
	if (relation == 'none') return;
	var Elements = hiddenFormFieldsPointers[relation];
	for (var i=0;i<Elements.length;i++)
	{
		waitingRoom.appendChild(Elements[i]);
		if (Elements[i].nestedRels)
			for (var j=0;j<Elements[i].nestedRels.length;j++)
				intoWaitingRoom(Elements[i].nestedRels[j]);
	}
}

function intoMainForm(relation)
{
	if (relation == 'none') return;
	var Elements = hiddenFormFieldsPointers[relation];
	for (var i=0;i<Elements.length;i++)
	{
		var insertPoint = document.getElementById(relation+i);
		insertPoint.parentNode.insertBefore(Elements[i],insertPoint);
		if (Elements[i].nestedRels)
		{
			var fields = getAllFormFields(Elements[i]);
			for (var j=0;j<fields.length;j++)
			{
				if (!fields[j].getAttribute('rel')) continue;
				if (fields[j].checked || fields[j].selected) 
					intoMainForm(fields[j].getAttribute('rel'));
			}
		}
	}
}

function getAllFormFields(node)
{
	var allFormFields = new Array;
	var x = node.getElementsByTagName('input');
	for (var i=0;i<x.length;i++)
		allFormFields.push(x[i]);
	var y = node.getElementsByTagName('option');
	for (var i=0;i<y.length;i++)
		allFormFields.push(y[i]);
	return allFormFields;
}

/** ULTRA-SIMPLE EVENT ADDING **/

function addEventUF(obj,type,fn)
{
	if (obj.addEventListener)
		obj.addEventListener(type,fn,false);
	else if (obj.attachEvent)
		obj.attachEvent("on"+type,fn);
}
addEventUF(window,"load",prepareForm);


/** PUSH AND SHIFT FOR IE5 **/

function Array_push() {
	var A_p = 0
	for (A_p = 0; A_p < arguments.length; A_p++) {
		this[this.length] = arguments[A_p]
	}
	return this.length
}

if (typeof Array.prototype.push == "undefined") {
	Array.prototype.push = Array_push
}

function Array_shift() {
	var A_s = 0
	var response = this[0]
	for (A_s = 0; A_s < this.length-1; A_s++) {
		this[A_s] = this[A_s + 1]
	}
	this.length--
	return response
}

if (typeof Array.prototype.shift == "undefined") {
	Array.prototype.shift = Array_shift
}


Once I import it back, I get the in IE Console found in the previous post. Any news on that?

The console highlights this code.

sup_number.addEvent('blur', function() {
    	// clear any background color from the input
    	sup_number.setStyle('background-color', 'white');
        // check that the email address is valid
        if (sup_number.length = 6 ) {
            // if all is well send the JSON request
            var jSonRequest = new Json.Remote(url, {
            	onComplete: function(r) {
                	// check the result and set the background color
                  	if ( r.sup_number_ok ) {
                    	sup_number.setStyle('background-color', '#66cc99');
                        site.value = r.sup_number_ok;
                  	} else {
                    	sup_number.setStyle('background-color', 'red');
                        site.value = "No site associated with that SUP number";
                  	}
                }
            }).send({'sup_number': sup_number.value});
        } else {
          	// if this isn't a valid sup number set background color red
          	sup_number.setStyle('background-color', 'red');
                site.value = "No site associated with that SUP number";
        }
    });


That particular addEvent seems to be empty.
quantum_leap 18 Jul, 2012
I activated the System - Mootools Upgrade plugin in Joomla and it seems to be working😑 . Judging by my current Chronoform version I might have lost some backend functionality by having the plugin activated but for the time being I am willing to take that risk!
GreyHead 18 Jul, 2012
Hi quantum_leap,

Please turn off the MooTools Upgrade plug-in and post (or PM) a link to the form so I can take a quick look.

Bob
GreyHead 20 Jul, 2012
Hi quantum_leap,

I got the PM but there was no link in it, should there have been?

Bob
GreyHead 21 Jul, 2012
Hi quantum_leap,

This appears to be working OK in FireFox, and IE9 in IE8 & IE9 mode - it fails for me with IE9 in IE7 mode and in Chrome. Though these differences may be a timing issue.

It is failing on the line
sup_number.addEvent('blur', function() {
and I think that what is happening is that the hideable forms code removes this input from the HTML when it hides it and then the Ajax code can't find it.

The answer is to add a check to make sure that sup_number exists before running the addEvent and then finding a way to re-add the event when the input is 'un-hidden'.

Bob
quantum_leap 21 Jul, 2012
In such a case it shouldn't be working in all browsers. And why does it work when I activate the moo tools upgrade plugin?
GreyHead 22 Jul, 2012
Hi quantum_leap,

It works when you turn off the hideable inputs or upgrade the MooTools library (which breaks the hidable input code) because then none of the inputs are hidden and so the Ajax addEvent code always finds the input.

The differences between browsers are because their JavaScript interpreters behave in slightly different ways when they find an error :-( There may also be some timing differences here about whether or not the input is already hidden when the Ajax addEvent is run.

Bob
This topic is locked and no more replies can be posted.