Drupal 8 add ajax form element after ajax callback - ajax

I am building a drupal form with multiple ajax enabled form elements.
I have one select list that does an ajax callback after change. The problem is that it adds a new select list to the page, which is also ajax enabled. This does not seem to work, which seems logical to me because the ajax is actually bundled an added to the page so it is lost in the replacecommand.
Is there anyone experienced with this, and does anyone have a solution ?
This is my code
/**
* {#inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state)
{
$form['city'] = [
'#type' => 'select',
'#title' => $this->t('Station'),
'#description' => $this->t('City'),
'#options' => array(
'Aalst' => $this->t('Aalst'),
'Brussel' => $this->t('Brussel'),
'Hasselt' => $this->t('Hasselt'),
'Leuven' => $this->t('Leuven'),
),
'#ajax' => [
'callback' => array($this, 'extendFormAjax'),
'event' => 'change',
'progress' => array(
'type' => 'throbber',
'message' => t('Choose City'),
),
],
'#suffix' => '<div id="extended-form"></div>',
];
$form['submit'] = [
'#type' => 'submit',
'#value' => t('Submit'),
];
return $form;
}
/**
* Ajax callback to validate the email field.
*/
public function extendFormAjax(array &$form, FormStateInterface $form_state)
{
$parking = [
'#type' => 'select',
'#title' => $this->t('Parking'),
'#description' => $this->t('Parking'),
'#options' => [
'P1' => $this->t('P1'),
'P2' => $this->t('P2'),
],
'#ajax' => [
'callback' => array($this, 'extendFormAjax'),
'event' => 'change',
'progress' => array(
'type' => 'throbber',
'message' => t('Choose parking'),
),
],
];
$response = new AjaxResponse();
$response->addCommand(new InsertCommand('#extended-form', $parking));
return $response;
}

I had a similar issue and i resolved it by adding the element in buildForm and adding a wrapper for it and sending the form element via HtmlCommand
/**
* {#inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state)
{
$form['city'] = [
'#type' => 'select',
'#title' => $this->t('Station'),
'#description' => $this->t('City'),
'#options' => array(
'Aalst' => $this->t('Aalst'),
'Brussel' => $this->t('Brussel'),
'Hasselt' => $this->t('Hasselt'),
'Leuven' => $this->t('Leuven'),
),
'#ajax' => [
'callback' => array($this, 'extendFormAjax'),
'event' => 'change',
'progress' => array(
'type' => 'throbber',
'message' => t('Choose City'),
),
],
];
$form['parking'] = [
'#prefix' => '<div id="extended-form">',
'#suffix' => '</div>',
'#type' => 'select',
'#title' => $this->t('Parking'),
'#description' => $this->t('Parking'),
'#options' => [
'P1' => $this->t('P1'),
'P2' => $this->t('P2'),
],
'#ajax' => [
'callback' => array($this, 'extendFormAjax'),
'event' => 'change',
'progress' => array(
'type' => 'throbber',
'message' => t('Choose parking'),
),
],
];
$form['submit'] = [
'#type' => 'submit',
'#value' => t('Submit'),
];
return $form;
}
/**
* Ajax callback to validate the email field.
*/
public function extendFormAjax(array &$form, FormStateInterface $form_state)
{
$parking = [
'#type' => 'select',
'#title' => $this->t('Parking'),
'#description' => $this->t('Parking'),
'#options' => [
'P1' => $this->t('P1'),
'P2' => $this->t('P2'),
],
'#ajax' => [
'callback' => array($this, 'extendFormAjax'),
'event' => 'change',
'progress' => array(
'type' => 'throbber',
'message' => t('Choose parking'),
),
],
];
$response = new AjaxResponse();
$response->addCommand(new HtmlCommand('#extended-form', $parking));
return $response;
}
Try it like this. I have not tested the code.

Try call somewhere in JS Drupal.attachBehaviors();

I experienced this issue and resolved it by this way :
For each element which were populated by Ajax, I add the property "#validated" => true and in the callback, the returned field must have the same attributes (id, name) that the original field :
$form['example_field'] = array(
'#type' => 'select',
'#required' => FALSE,
'#options' => getDynamicOptions(),
'#prefix' => '<div id="etablissement-type-wrapper">',
'#suffix' => '</div>',
'#attributes' => [
'data-drupal-selector' => "edit-example",
'id' => "edit-example",
'name' => "example",
],
'#validated' => TRUE,
);

You need add ajax elements in buildForm methods and rebuild form. Something like this:
/**
* {#inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, $no_js_use = FALSE) {
// We want to deal with hierarchical form values.
$form['#tree'] = TRUE;
$form['step'] = [
'#type' => 'value',
'#value' => !empty($form_state->getValue('step')) ? $form_state->getValue('step') : 1,
];
switch ($form['step']['#value']) {
case 1:
$limit_validation_errors = [['step']];
$form['step1'] = [
'#type' => 'fieldset',
'#title' => $this->t('Step 1: Personal details'),
];
$form['step1']['name'] = [
'#type' => 'textfield',
'#title' => $this->t('Your name'),
'#default_value' => $form_state->hasValue(['step1', 'name']) ? $form_state->getValue(['step1', 'name']) : '',
'#required' => TRUE,
];
break;
case 2:
$limit_validation_errors = [['step'], ['step1']];
$form['step1'] = [
'#type' => 'value',
'#value' => $form_state->getValue('step1'),
];
$form['step2'] = [
'#type' => 'fieldset',
'#title' => t('Step 2: Street address info'),
];
$form['step2']['address'] = [
'#type' => 'textfield',
'#title' => $this->t('Your street address'),
'#default_value' => $form_state->hasValue(['step2', 'address']) ? $form_state->getValue(['step2', 'address']) : '',
'#required' => TRUE,
];
break;
case 3:
$limit_validation_errors = [['step'], ['step1'], ['step2']];
$form['step1'] = [
'#type' => 'value',
'#value' => $form_state->getValue('step1'),
];
$form['step2'] = [
'#type' => 'value',
'#value' => $form_state->getValue('step2'),
];
$form['step3'] = [
'#type' => 'fieldset',
'#title' => $this->t('Step 3: City info'),
];
$form['step3']['city'] = [
'#type' => 'textfield',
'#title' => $this->t('Your city'),
'#default_value' => $form_state->hasValue(['step3', 'city']) ? $form_state->getValue(['step3', 'city']) : '',
'#required' => TRUE,
];
break;
}
$form['actions'] = ['#type' => 'actions'];
if ($form['step']['#value'] > 1) {
$form['actions']['prev'] = [
'#type' => 'submit',
'#value' => $this->t('Previous step'),
'#limit_validation_errors' => $limit_validation_errors,
'#submit' => ['::prevSubmit'],
'#ajax' => [
'wrapper' => 'ajax-example-wizard-wrapper',
'callback' => '::prompt',
],
];
}
if ($form['step']['#value'] != 3) {
$form['actions']['next'] = [
'#type' => 'submit',
'#value' => $this->t('Next step'),
'#submit' => ['::nextSubmit'],
'#ajax' => [
'wrapper' => 'ajax-example-wizard-wrapper',
'callback' => '::prompt',
],
];
}
if ($form['step']['#value'] == 3) {
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t("Submit your information"),
];
}
$form['#prefix'] = '<div id="ajax-example-wizard-wrapper">';
$form['#suffix'] = '</div>';
return $form;
}
public function prompt(array $form, FormStateInterface $form_state) {
return $form;
}
public function nextSubmit(array $form, FormStateInterface $form_state) {
$form_state->setValue('step', $form_state->getValue('step') + 1);
$form_state->setRebuild();
return $form;
}
public function prevSubmit(array $form, FormStateInterface $form_state) {
$form_state->setValue('step', $form_state->getValue('step') - 1);
$form_state->setRebuild();
return $form;
}
public function submitForm(array &$form, FormStateInterface $form_state) {
$messenger = \Drupal::messenger();
$messenger->addMessage($this->t('Your information has been submitted:'));
}

Related

Cake PHP 2.8.0 not validating

I have the folowing validate inside my Workshops class
public $validate = array(
'programa'=> array(
'allowEmpty' => false,
'required' => true
),
'lugar'=> array(
'allowEmpty' => false,
'required' => true
),
'fecha_inicio'=> array(
'allowEmpty' => false,
'required' => true
),
'fecha_fin'=> array(
'allowEmpty' => false,
'required' => true
),
'objetivo'=> array(
'allowEmpty' => false,
'required' => true
),
'instructor'=> array(
'allowEmpty' => false,
'required' => true
)
);
however when I save with empty fields a record is created in the database, the validation is not being done.
This is the code for my add form
<h1>Agregar Taller</h1>
<?php
echo $this->Form->create('Workshop');
echo $this->Form->input('nombre');
echo $this->Form->input('fecha_inicio',
array(
'label' => 'Fecha Inicio',
'dateFormat' => 'DMYhm',
'minYear' => date('Y') - 0,
'maxYear' => date('Y') + 2,
));
echo $this->Form->input('fecha_fin',
array(
'label' => 'Fecha fin',
'dateFormat' => 'DMYhm',
'minYear' => date('Y') - 0,
'maxYear' => date('Y') + 2,
));
echo $this->Form->input('caracteristica_tec21');
echo $this->Form->input('programa');
echo $this->Form->input('lugar');
echo $this->Form->input('instructor');
echo $this->Form->input('objetivo', array('rows' => '3'));
echo $this->Form->end('Guardar Taller');
?>
And here is my controller
<?php
class WorkshopsController extends AppController {
public $helpers = array('Html', 'Form');
public function index() {
$this->set('workshops',$this->Workshop->find('all'));
}
public function view($id = null){
if(!$id){
throw new NotFoundException(__('Taller inválido'));
}
$workshop = $this->Workshop->findById($id);
if (!$workshop) {
throw new NotFoundException(__('Taller inválido'));
}
$this->set('workshop', $workshop);
}
public function add() {
if ($this->request->is('post')) {
$this->Workshop->create();
if ($this->Workshop->save($this->request->data)) {
$this->Flash->success(__('El taller se ha agregado'));
return $this->redirect(array('action' => 'index'));
}else{
$this->Flash->error(__('No se ha podido agregar el taller'));
}
}
}
}
?>
You suppose to add a message field in every form field's validation, this is the message which shown in view file. Please see the below:
public $validate = array(
'programa' => array(
'allowEmpty' => false,
'required' => true,
'message' => "Please Enter the programa."
),
'lugar' => array(
'allowEmpty' => false,
'required' => true,
'message' => "Please Enter the lugar."
),
'fecha_inicio' => array(
'allowEmpty' => false,
'required' => true,
'message' => "Please Enter the fecha_inicio."
),
'fecha_fin' => array(
'allowEmpty' => false,
'required' => true,
'message' => "Please Enter the fecha_fin."
),
'objetivo' => array(
'allowEmpty' => false,
'required' => true,
'message' => "Please Enter the objetivo."
),
'instructor' => array(
'allowEmpty' => false,
'required' => true,
'message' => "Please Enter the instructor."
)
);
If the answer is correct, Please don't forget to mark it as a answer.

filter_condition_callback not working in Magento observer

I am working on a custom extension, when i use filter_condition_callback in observer inside addColumnAfter() its not working kindly give me some solution to this.
class CustomGrid_GeneProductGrid_Model_Observer
{
public function beforeCollectionLoad(Varien_Event_Observer $observer)
{
$collection = $observer->getCollection();
if (!isset($collection)) {
return;
}
if ($collection instanceof Mage_Catalog_Model_Resource_Product_Collection) {
$store = Mage::app()->getRequest()->getParam('store');
$collection->joinAttribute('special_price', 'catalog_product/special_price', 'entity_id', null, 'left', $store);
$collection->addAttributeToSelect('cost');
$collection->addAttributeToSelect('m_cost');
}
}
public function customGridHtmlBefore(Varien_Event_Observer $observer)
{
$store = Mage::app()->getRequest()->getParam('store');
$grid = $observer->getBlock();
if ($grid instanceof Mage_Adminhtml_Block_Catalog_Product_Grid) {
if ($store == '') {
$grid->addColumnAfter(
'expend_stores', array(
'header' => 'Expend Stores',
'filter' => false,
//'index' => 'color',
'width' => '25px',
'renderer' => 'customgrid_geneproductgrid/adminhtml_product_ExpendCollapse',
'align' => 'center',
), 'massaction'
);
}
$storeId = (int)Mage::app()->getRequest()->getParam('store', 0);
$store = Mage::app()->getStore($storeId);
$grid->addColumnAfter(
'cost', array(
'header' => 'V-Cost',
'index' => 'cost',
'type' => 'price',
'currency_code' => $store->getBaseCurrency()->getCode(),
'width' => '25px',
'align' => 'center',
), 'sku'
);
$grid->addColumnAfter(
'm_cost', array(
'header' => 'M-Cost',
'index' => 'm_cost',
'type' => 'price',
'currency_code' => $store->getBaseCurrency()->getCode(),
'width' => '25px',
'align' => 'center',
), 'cost'
);
$grid->addColumnAfter(
'special_price', array(
'header' => 'Special Price',
'index' => 'special_price',
'type' => 'price',
'currency_code' => $store->getBaseCurrency()->getCode(),
'width' => '25px',
'align' => 'center',
), 'price'
);
$grid->addColumnAfter('accessories_category_list', array(
'header' => Mage::helper('catalog')->__('Category'),
'index' => 'accessories_category_list',
'sortable' => false,
'type' => 'options',
'options' => Mage::getSingleton('customgrid_geneproductgrid/system_config_source_Category')->toOptionArray(),
'renderer' => 'customgrid_geneproductgrid/adminhtml_catalog_product_grid_render_category',
'filter_condition_callback' => array(Mage::getSingleton('customgrid_geneproductgrid/observer'), 'filterCallback'),
), 'set_name');
$grid->sortColumnsByOrder();
}
}
public function filterCallback($collection, $column)
{
$value = $column->getFilter()->getValue();
$_category = Mage::getModel('catalog/category')->load($value);
$collection->addCategoryFilter($_category);
return $collection;
}
}

Zf2 entity create a custom filters

public function getInputFilter($em){
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
$inputFilter->add(array(
'name' => 'fullName',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim'),
array('name' => 'SpecialChar')
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 5,
'max' => 100,
),
),
),
));
$inputFilter->add(array(
'name' => 'password',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 1,
'max' => 100,
),
),
),
));
$inputFilter->add(array(
'name' => 'email',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'EmailAddress',
),
array(
'name' => 'User\Validator\NoEntityExists',
'options'=>array(
'entityManager' =>$em,
'class' => 'User\Entity\User',
'property' => 'email',
'exclude' => array(
array('property' => 'id', 'value' => $this->getId())
)
)
)
),
));
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
I want to add a new function in entity called "Special Char" in all input fields, so how does one create a custom filter in a doctrine entity.
I want to add validation to avoid special char in entity because I need to use this in n no of places.
How do I implement this?
From Zend documentation:
namespace Application\Filter;
use Zend\Filter\FilterInterface;
class MyFilter implements FilterInterface
{
public function filter($value)
{
// perform some transformation upon $value to arrive on $valueFiltered
return $valueFiltered;
}
}
Then you should be able to do:
$inputFilter->add(array(
'name' => 'fullName',
'required' => true,
'filters' => array(
array('name' => 'Application\Filter\MyFilter')
…

Ajax replace method does not working error

Ajax replace method doesn't working in these code.But append method is working.
<?php
$currentDate = date("Y-m-d");
$currentTime = date("Y-m-d");
global $user;
function form_test_permission()
{
return array(
'submit_form_test' =>array(
'title' =>t('Submit_form_test'),
'description' => t('Submit the form_test form'),
),
);
}
function form_test_menu() {
$items = array();
$items['production'] = array(
'title' =>'Production',
'type' => MENU_NORMAL_ITEM,
'access arguments' => array('submit_form_test'),
'page callback' => 'drupal_get_form',
'page arguments' => array('form_test_form'),
);
return $items;
}
function form_test_form($form,&$form_state) {
$form['production'] = array(
'#title' => t('production'),
'#type' => 'hidden',
'#value'=> '1',
);
$form['production1'] = array(
'#title' => t('production1'),
'#type' => 'hidden',
);
$form['production_date'] = array(
'#title' => t('production_date'),
'#type' => 'hidden',
'#value' => date('Y-m-d'),
);
$form['production_time'] = array(
'#title' => t('production_time'),
'#type' => 'hidden',
'#value' => date('H:i:s'),
);
$form['production23'] = array(
'#title' => t('production23'),
'#type' => 'hidden',
'#value'=> '1',
);
$form['button2'] = array(
'#value' => 'UNDO',
'#type' => 'submit',
'#prefix' => '<div class="test">',
'#suffix' => '</div>',
'#submit' => array('form_test_form_button2'),
);
$form['button1'] = array(
'#value' => ' ADD ',
'#type' => 'submit',
'#prefix' => '<div class="test1">',
'#suffix' => '</div>',
'#submit' => array('form_test_form_button1'),
'#ajax' => array(
'callback' => 'ajax_example_submit_driven_callback',
'method' => 'replace',
'effect' => 'fade',
'event' =>'click',
'wrapper' => 'countvalue',
),
);
$form['start_counter'] = array(
'#type' => 'select',
'#options' => array (
'Start' => 'Start',
'2501 ' => '2501 ',
'302 ' => '302 ',
'1107 ' => '1107',
'1104' => '1104',
'0106' => '0106',
'0305' => '0305',
'0103' => '0103',
),
'#prefix' => ' <div class="box chart gradient" style="width:30%;float:left;margin-top: -186px;">
<div class="title">
<h4>
<span style="text-align:center;">Downtime</span>
</h4>
</div>
<div class="content" style="padding-bottom:0;">
<p class="dowtime-show" id="counter"></p>',
);
$form['start_counter1'] = array(
'#type' => 'textfield',
);
$form['stop_counter'] = array(
'#type' => 'select',
'#options' => array (
'Stop'=>'Stop',
'Mechanical' => 'Mechanical',
'Electrical' => 'Electrical',
'Programming' => 'Programming',
'Setup' => 'Setup',
'PlannedMaintenance' => 'PlannedMaintenance'
),
'#suffix' => '</div> </div>',
);
$form['counter'] = array(
'#type' => 'textfield',
);
$form['button3'] = array(
'#value' => 'submit',
'#type' => 'submit',
'#submit' => array('form_test_form_button3'),
);
return $form;
}
function ajax_example_submit_driven_callback($form,$form_state){
$result = db_query("SELECT * FROM form_test WHERE production_date='2014-02-10' and production_time between '01:00:00' and '02:00:00'");
$prod_1= $result->rowcount();
$form['#tree'] = TRUE;
$form_state['rebuild'] = TRUE;
return 'count value is:'.$prod_1.'';
}
function form_test_form_button1($form,&$form_state){
$ft_id = db_insert('form_test')
->fields(array(
'production' => $form_state['values']['production'],
'production_date' => $form_state['values']['production_date'],
'production_time' => $form_state['values']['production_time'],
'production1' => $form_state['values']['production1'],
))
->execute();
$form_state['rebuild'] = true;
}
function form_test_form_button2($form,&$form_state){
$ft_id = db_insert('form_test1')
->fields(array(
'production23' => $form_state['values']['production23'],
'production_date' => $form_state['values']['production_date'],
'production_time' => $form_state['values']['production_time'],
))
->execute();
}
function form_test_form_button3($form,&$form_state){
$ft_id = db_insert('downtime1')
->fields(array(
'start_counter1' => $form_state['values']['start_counter1'],
'stop_counter' => $form_state['values']['stop_counter'],
'counter' => $form_state['values']['counter'],
'production_date' => $form_state['values']['production_date'],
'production_time' => $form_state['values']['production_time'],
))
->execute();
}
I spend a lot of hours to get the result but cannot able to get it.Anybody know how to solve these kind of Errors.The main problem is that it doesn't change the value while using replace method.

ajax function in drupal 6 not working

I need to filter the territory field upon the value of the region field im using ajax function like it's mentioned in the below code but it's not working. THE AJAX CALL on the fonction is not getting into the function 'territory_filter_callback' anyway would know where is the error?
function form_search_menu() {
$items['form/search'] = array(
'title' => t('Search'),
'page callback' => 'drupal_get_form',
'page arguments' => array('_search'),
'access callback' => TRUE,
'description' => t('search'),
);
return $items;
}
function _search(&$form_state) {
drupal_add_js(drupal_get_path('module', 'form_search') .'/script.js');
$form['description'] = array(
'#type' => 'item',
'#title' => t('Search page'),
);
//FILL THE LIST OF REGIONS
$conn = oci_connect('webuser', 'website', '172.16.1.1');
//regions
$stid = oci_parse($conn, "SELECt code,descr1 FROM table1.region");
oci_execute($stid);
$cidades = array(); while (($row = oci_fetch_array($stid, OCI_ASSOC))) {
$cidades[$row['CODE']]= $row['DESCR1'];
} $cidades ['']='Select';
//city
$stid1 = oci_parse($conn, "SELECT code,descr1 from table1.city ORDER BY DESCR1"); oci_execute($stid1); $types = array(); while (($row = oci_fetch_array($stid1, OCI_ASSOC))) {
$types [$row['CODE']]= $row['DESCR1'];
} $types['']='Select';
//territory
$stid2 = oci_parse($conn, "SELECT code,descr1 FROM table1.territory"); oci_execute($stid2);
$territory = array();
while (($row = oci_fetch_array($stid2, OCI_ASSOC))) {
$territory [$row['CODE']]= $row['DESCR1'];
}
$territory ['']='Select';
oci_free_statement($stid);
oci_close($conn);
$form['name'] = array(
'#type' => 'fieldset',
//'#title' => t('Name'),
// Make the fieldset collapsible.
'#collapsible' => false, // Added
'#collapsed' => FALSE, // Added
);
$form['name']['Region'] = array(
'#type' => 'select',
'#title' => t('Region'),
'#options' => $cidades,
'#required' => FALSE, '#default_value' => isset($form_state['values']['name']['Region']) ? $form_state ['values']['name']['Region'] : '',
'#ajax' => array(
'event' => 'change',
'callback' => 'territory_filter_callback',
'wrapper' => 'dropdown_second_replace'
),
// Added
);
$form['name']['Territory'] = array(
'#type' => 'select',
'#title' => t('Territory'), '#prefix' => '<div id="dropdown_second_replace">', '#suffix' => '</div>',
'#options' => $territory,
'#required' => FALSE, '#default_value' => isset($form_state['values']['name']['Territory']) ? $form_state['values']['name']['Territory'] : '',
// Added );
$form['name']['City'] = array(
'#type' => 'select',
'#title' => t('City'),
'#options' => $types,
'#required' => FALSE,
// Added
);
$form['link'] = array(
'#type' => 'markup',
'#value' => '<a href="#" onclick="navigate()" ><input type="button" value="Search" style="background-color:#2A64A9;color:#FFFFFF;width:80px; height:25px; border:1;CURSOR:POINTER;float:right;border-color:#FFFFFF;" ></a>', //
return $form;
}
function territory_filter_callback(&$form,&$form_state)
{
$territory_options=array();
if(isset($form['name']['Region']['#default_value']['0'])
{ $Region=$form['name']['Region']['#default_value']['0'];
}
else
{ $Region=0;
}
$territory_options=selected_territory($Region);
$form['name']['Region']['#ajax']=
array('event' => 'change',
'wrapper' => 'territory_wrapper',
'callback' => 'filter_territory_callback',
'method' =>replace,
);
$form ['name']['territory']['prefix']='<div id="territory_wrapper">';
$form ['name']['territory']['prefix']='</div>';
$form ['territory']['#options']=$territory_options;
}
function filter_territory_callback($form,$form_state)
{
$Region=$form['name']['Region']['#value'];
$form['name']['territory']['#options']=selected_territory($Region);
return $form['territory'];
}
drupal 6 not support '#ajax'...'#ajax' is working with drupal 7...in drupal 6 you can use '#ahah'
http://drupal.org/node/331941
good luck

Resources