Prepopulating form and making readonly

Tom0 26 Jan, 2009
Hi,

I am trying to set up a system which someone with no technical experience can create a new form using only the chronoforms wizard and with a "Save" button and a change of submit url, will be able to save data to the database and load data into the form. I cant seem to find a way of posting database data back to the form (I have taken the post data and turned it to a string for storage). The work-around I came up with is below (here the $data is an associative array of name-value pairs).

///--- Sends database post data back into a form and posts it to chronoforms...
function formdataGateway($url,$data=NULL,$readonly='false') {
	$html = '<form name="tempform" method="post" action="'.$url.'">';
	if ($data) { 
		foreach ($data as $n=>$v) { 
			$html .= '<input type="hidden" name="'.$n.'" value="'.$v.'" />';
		}
	}
	$html .= '<input type="hidden" name="readonly" value="'.$readonly.'" />';
	$html .= '</form>
			    <script type="text/javascript">
				window.addEvent(\'domready\', function() {
					document.tempform.submit();			
				});
				</script>';
	echo $html;
}


Also in the chronocontact.html.php I had to change line 112 from
if (($posted)&&($paramsvalues->captcha_dataload))
to just
if ($posted)
to make sure the bit of javascript gets input to read the posted data back to the form.

This works fine EXCEPT of course it has to reach the page and load completely until the javascript is called to submit the form. This means loading times are very slow. Do you know of any better way to do this?


Also, I put in a "readonly" post value above, I put some more code into the chronocontact.html.php to make the form completely readonly (which is decided on more factors in my custom component) but for anyones interest heres my code (line 166 - although my line numbers may be messed up now!!)

<?php ///tom- make form readonly!
				$readonly = $post['readonly']; 
				if ($readonly=='true') { ?>
				
				window.addEvent('domready', function() {
					var form = document.<?php echo "ChronoContact_".$rows[0]->name; ?>;
					if (form.hasChildNodes()) {
				    	var children = form.getElementsByTagName('*');
					    for(var c=0; c < children.length; c++) {
					    	if (children[c].name) {
						    	var a = children[c].name.substr(0,5);
						    	if (a=='radio' || a=='formt') {
						    		children[c].disabled = true;
						    	}
						    	children[c].readOnly = true;
					    	}
					    }
					}
				});
			<?php } ?>


Again, if anyone knows of a better way of doing this I would love to know!!!

Thanks again for a great component!

Tom
Max_admin 27 Jan, 2009
Hi Tom,

Sorry but I can't understand much, whats the problem with the current form wizard approach ?

Cheers
Max
Max, ChronoForms developer
ChronoMyAdmin: Database administration within Joomla, no phpMyAdmin needed.
ChronoMails simplifies Joomla email: newsletters, logging, and custom templates.
Tom0 02 Feb, 2009
Hi Max,

Sorry for the slow reply!

The current form wizard approach is fine for the creation of new forms. However in my component I want to save the form data from ANY form into a database and load this data back into the form when the user reopens it. The way I outlined in my previous post involves turning the post array FROM the form into a string to store in the database when saving. When loading it outputs a page with a hidden form with all the name-values of the original form and POSTS it back TO the form onload (using javascript). I edited some of your code to make sure these fields are then populated on load from this posted data.

The problem is that the user has to wait to load all of the data to this temporary form and wait for everything to load and display headers/footers etc before it is sent over to the chrono-form - doubling loading time.

The other question was about making the form completely readonly - for which I think my solution is ok (makes readonly onload using javascript again) but while the page is laoding user can still mess with the form - not ideal.

Cheers,
Tom
Max_admin 02 Feb, 2009
Hi Tom,

I'm not sure how do you load the user's records (using the user id ? ) but you can add some PHP code to your form to load the data inside the fields too, and you can add some PHP statements to turn fields as read only when some data is loaded, this is of course better than the JS approach which may fail..

Regards
Max
Max, ChronoForms developer
ChronoMyAdmin: Database administration within Joomla, no phpMyAdmin needed.
ChronoMails simplifies Joomla email: newsletters, logging, and custom templates.
Tom0 03 Feb, 2009
Hi Max,

This is what Iv come up with, in chronocontact.html.php right before the line:

eval( "?>".$rows[0]->html );



$post = JRequest::get( 'post' , JREQUEST_ALLOWRAW );
$aid = JRequest::getVar( 'aid' ); /// pass this variable to chronoforms to tell it to work like part of my component ///
$readonly = $post['readonly']; 

// make readonly if required:
if ($readonly=='true') {
	$rows[0]->html = str_replace('type="radio"', 'type="radio" disabled', $rows[0]->html);
	$rows[0]->html = str_replace('type="text"','type="text" readOnly', $rows[0]->html);
	$rows[0]->html = str_replace('type="submit"','type="submit" disabled', $rows[0]->html);
	$rows[0]->html = str_replace('textarea','textarea readOnly', $rows[0]->html);
}
			
// prepopulate form if required
if ($aid && $posted) {
	$post = JRequest::get( 'post' , JREQUEST_ALLOWRAW );
	foreach($post as $name => $value){
	        $rows[0]->html = str_replace('name="'.$name.'"', 'name="'.$name.'" value="'.$value.'"',  $rows[0]->html);
	}			
}


This removes any need for javascript.

It still requires my component to post the user data from a form- loading the relavent data string from the database, converting to an array, writing it to a form, rendering the page and having a bit of javascript to say "when page loaded, submit form to the chronoform page". This means that page has to be loaded first before redirecting to the actual form.

Do you know if there is a way of passing the post array directly to the chronoform page without physically creating an interim form and submitting it? I have tried JRequest::setVar($name,$value,'post') and then using $mainframe->redirect but the post data doesnt seem to get passed.

Thanks,
Tom
Max_admin 03 Feb, 2009
Hi Tom,

good idea but for textareas it may not work because the textarea doesn't have a value attribute!

anyway, I think you can replace :
$post = JRequest::get( 'post' , JREQUEST_ALLOWRAW );


with some line of code to load your record from the database ?

Cheers
Max
Max, ChronoForms developer
ChronoMyAdmin: Database administration within Joomla, no phpMyAdmin needed.
ChronoMails simplifies Joomla email: newsletters, logging, and custom templates.
Tom0 04 Feb, 2009
Hi Max,

ok so I have put my queries in the chronocontact.php file and also:


if (!is_null($dataObj->submitted)) {
        $posted['readonly'] = 'true';
}
if ($dataObj->sent_data) { 
	foreach ($data as $n=>$v) { 
		$posted[$n] = $v;
	}
}


so now the data gets put straight into the $posted variable which gets passed to chronocontact.html.php.

I have got around the text area problem by changing the code like so: (bit messy though!)


// prepopulate form if required
if ($aid && $posted) {
        foreach($posted as $name => $value){
		$namepos = strpos($rows[0]->html , 'name="'.$name.'"');
		if ( strpos($rows[0]->html, '</textarea', $namepos) == strpos($rows[0]->html, '</', $namepos) ) {	
			$tmpstr = substr($rows[0]->html, $namepos, strpos($rows[0]->html , '>', $namepos)-$namepos+1);
			$rows[0]->html = str_replace($tmpstr, $tmpstr.$value, $rows[0]->html);
		} else {
			$rows[0]->html = str_replace('name="'.$name.'"',
										 'name="'.$name.'" value="'.$value.'"',
										  $rows[0]->html);						  
		}
	}			
}


Ok hope that should do it! My chrono-files are looking fairly hacked up at the moment I think they need a clean but it is definitely worth having that extra code in here to avoid the double-load (and now the browser-back-button works again!)

Thanks a lot for your help Max!

Tom
Tom0 04 Feb, 2009
That code didnt work for radio buttons, this seems to do it though:



// prepopulate form if required
if ($aid && $posted) {
	foreach($posted as $name => $value){
		$namepos = strpos($rows[0]->html , 'name="'.$name.'"');
		if ( strpos($rows[0]->html, '</textarea', $namepos) == strpos($rows[0]->html, '</', $namepos) ) {  /// text area case
					
			$tmpstr = substr($rows[0]->html, $namepos, strpos($rows[0]->html , '>', $namepos)-$namepos+1);
			$rows[0]->html = str_replace($tmpstr, $tmpstr.$value, $rows[0]->html);
				
		} elseif ((strpos($rows[0]->html, 'type="radio"', $namepos) < strpos($rows[0]->html, '>', $namepos))) {   /// radio case

			$pattern = '/value="'.$value.'"[^>]*name="'.$name.'"/';
					
			preg_match($pattern, $rows[0]->html, $matches);
							
			foreach ($matches as $match) {
				$rows[0]->html = str_replace($match, $match . ' checked', $rows[0]->html);	
			}
								
		} else {								
			$rows[0]->html = str_replace('name="'.$name.'"', 'name="'.$name.'" value="'.$value.'"', $rows[0]->html);
		}
	}
}



Im guessing that wont be the end of it (selects? checkboxes?), but i'll keep posting any updates here - hopefully someone will find it helpful.
Max_admin 04 Feb, 2009
Glad you did it, I'm sure its not so easy the way you do it, and may be "code dependent", but I'm excited to see the final version of the code, I should do something similar for the profile plugin of Chronoforms after the new release, so thank you for sharing this!🙂

Regards,
Max
Max, ChronoForms developer
ChronoMyAdmin: Database administration within Joomla, no phpMyAdmin needed.
ChronoMails simplifies Joomla email: newsletters, logging, and custom templates.
This topic is locked and no more replies can be posted.