问题已经解决,请参阅下面的第3条评论,以获取使其全部工作的示例。

感谢Wim Leers和Kat Bailey以及很多关于AHAH的网站。我也感谢我的大脑留在我脑海中,而我在Drupal 6中围绕AHAH的整个概念进行了提交。

评论

katbailey的头像

您需要首先确保您的表单将对$ form_state做出反应,即它将始终根据$ form_state中的内容进行构建。在您的特定情况下,这意味着在您构建房间下拉列表时,在您的表单功能中,首先检查您是否具有选定的位置ID并基于此填充它。因此,您将调用一个函数来查找所选位置的房间,这是您的SQL查询所在的位置,而不是在您的回调中。这样,当您的ahah回调呈现表单时,它将使用实际的盖子值来执行此操作,然后您的房间下拉列表将对此做出反应。“快速选项卡”模块为其“显示”显示下拉列表执行此操作,以便您可以查看其中以更好地了解其工作原理。

Predated的图片

谢谢凯特:)

我实际上发现了你的博客文章,关于你在Quicktabs中所做的更新,你在那里讨论了所有这些,我只是没有回复它。我很确定我在这一点上已经敲定了,但是我正在研究的另一个项目让它的优先级提升了,我没有机会回到它。

我认为我让AHAH变得比现在复杂得多,我对此感到非常沮丧。在没有看到它几天之后再回过头来做出了很大的改变。当我让它工作时,我将不得不回到这里。

Predated的图片

我之前得到了它的工作,并且从来没有在这里发布它。但是为了在路上拯救某些人的挫折感,有一个例子,你需要在最低限度以下。请注意,示例代码尚未经过测试。

你想看看:
在D6中以正确的方式做AHAH 
Wim Leers关于ahah_helper 
的博客文章Kat Bailey关于表格二元性的博客文章

首先,您需要一个菜单回调:

function simple_menu() {
  $items['simple/js'] = array(
    'type' => MENU_CALBACK,
    'page callback' => 'simple_ahah_render',
    'access callback' => TRUE,
  );
  return $items;
}

当然,你需要一个表格:

function simple_form($form_state) {  
  $form['content'] = array(
    '#tree' => TRUE,
    '#prefix' => '<div id="simple-select-wrapper">',
    '#suffix' => '</div>',
  );
  $form['content']['simple_select_parent'] = array(
    '#type' => 'select',
    '#default_value' => $form_state['storage']['category']['select_cat'],
    '#options' => simple_get_options(),  // Get some options for this select from the DB
    '#ahah' => array(
      'path' => 'simple/js',
      'wrapper' => 'simple-select-wrapper',
    ),
  );
  
  // Here we react to $form_state, adding content to the form, depending on the
  // submitted value of simple_select_parent, above.
  if ($form_state['storage']['content']['simple_select_parent']) {
    $form['content']['simple_select_child'] = simple_ahah_select($form_state);
  }
  
  return $form;
}

而且您还需要以某种方式获取选择字段的选项 - 此函数将从数据库中提取它:

/**
 * Return a FAPI select element whose options are based on values submitted by a
 * separate select field.
 *
 * @param array $form_state 
 *     The submitted values of a form. We're mostly interested in $form_state['storage'] 
 *     which is where all the pertinent information will be.
 * @return array $element
 */
function simple_ahah_select($form_state) {
  $sql = "SELECT id, name FROM {your_db_table} WHERE id = %d";
  
  if ($form_state['storage']['content']['simple_select_parent']) {
    $result = db_query($sql, $form_state['storage']['content']['simple_select_parent']);
    while (($data = db_fetch_object($result)) !== FALSE) {
      $opt[$data->id] = $data->name;
    }
  }
  $element = array(
    '#type' => 'select',
    '#options' => $opt,
  );
  return $element;
}

神奇的一切都发生在你的AHAH回调函数中,在本例中是simple_ahah_render:

function simple_ahah_render() {
  $form_state    = array('storage' => NULL, 'submitted' => FALSE);
  $form_build_id = $_POST['form_build_id'];
  
  $form    = form_get_cache($form_build_id, $form_state);
  $args    = $form['#parameters'];
  $form_id = array_shift($args);
  
  $form['#post']       = $_POST;
  $form['#redirect']   = FALSE;
  $form['#programmed'] = FALSE;
  $form_state['post']  = $_POST;
  
  // Prevents _form_builder_ie_cleanup() from incorrectly assigning the
  // first button in the form as the clicked button.
  // Wim Leers' AHAH Helper Module has more in-depth information.
  // @see the ahah_helper project
  $form_state['submitted'] = TRUE;
  
  drupal_process_form($form_id, $form, $form_state);
  
  // Once drupal_rebuild_form is called, we no longer have access to 
  // $form_state['values'], so we merge it into $form_state['storage'].
  if (isset($form_state['values'])) {
    if (!isset($form_state['storage'])) {
      $form_state['storage'] = array();
    }
    $storage = $form_state['storage'];
    $values  = $form_state['values'];
    $form_state['storage'] = array_smart_merge($storage, $values);
  }
  
  // Rebuild the form.
  $form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id);
  
  // IMPORTANT:
  // This is a simple example, and we know what the new form element is called. In a
  // real world scenario, you would need to pass a callback function to this AHAH
  // render function that would return the new content, or get the new content in
  // some other way - this is just a simple example.
  $output = $form['content']['simple_select_child'];
  
  // Get the JS settings so we can merge them.
  $javascript = drupal_add_js(NULL, NULL, 'header');
  $settings = call_user_func_array('array_merge_recursive', $javascript['setting']);
  
  drupal_json(array(
    'status'    => TRUE,
    'data'      => theme('status_messages') . drupal_render($output),
    'settings'  => array('ahah' => $settings['ahah']),
  ));
}


/**
 * Smarter version of array_merge_recursive: overwrites scalar values.
 * 
 * This also came (like a God send) from Wim's AHAH helper module. Really, that's the
 * easiest way to go, and the module works like a charm - but I wanted to get my
 * head around the whole AHAH thing, and maybe you do to, or maybe you can't or don't
 * want to be dependant on a different module.
 * 
 * @see PHP Manual on: array-merge-recursive comment #82976.
 */
function array_smart_merge($array, $override) {
  if (is_array($array) && is_array($override)) {
    foreach ($override as $k => $v) {
      if (isset($array[$k]) && is_array($v) && is_array($array[$k])) {
        $array[$k] = array_smart_merge($array[$k], $v);
      }
      else {
        $array[$k] = $v;
      }
    }
  }
  return $array;
}
javier.ortiz.llerena的头像

我得到了它的工作,
忘了我的最后一条消息

嗨,
首先感谢您帮助您的工作并与drupalers分享,
但对于像我这样的人来说,
如果您可以发布一个有效工作示例的完整代码,那么在durpal世界中更多的新手会非常有用。

我一直在看这两天,我无法使它工作。
对于那个很抱歉。

wheelercreek的头像

我认为我的大脑确实爆炸了,但感谢大家写下来!最后我没有得到“Drupal检测到非法行为”的错误。

rgutierrezc的头像

感谢发布这个,这正是我想要的。

通过构建代码,我已经能够创建我期望的表单; 然而,当我提交它时,它不会使用$ form ['#redirect']属性,我已经尝试在几乎代码的每个部分设置; 它会继续回到表单。没有意义,因为从理论上讲,回调函数只会重新加载由包装器分隔的代码,但显然我在这里遇到了错误。

有关解决这个问题的任何想法?

蒂莫斯的照片

嗨,非常感谢这个howto!
我正在寻找一个解决方案,从选择字段填充自动填充文本字段的列表,您的主题给了我第一步。如果您想看一下,
我会在http://drupal.org/node/812956上给出一些精确度如果可以,我会对反馈非常感兴趣。
但现在,我将去检查一下帮助模块做什么,也许它可能有用!(但是我看到使用统计曲线有点特别......你知道为什么只有几个月会有很大的增加和减少吗?)

蒂姆巴雷特

Craz的头像

我试图将你的代码应用到我的模块,但与另一个例子一样,我得到一个弹出“错误发生”的弹出窗口

这是整个代码

在matches.module中

function matches_menu() {

  $items = array();

  $items['admin/esport'] = array(
    'title' => 'Esport',
    'description' => 'Dedicated esport module',
    'page callback' => 'matches_admin_page',
    'page arguments' => array('matches_admin'),
    'access arguments' => array('access administration pages'),
	'file' => 'matches.list.admin.inc'
   );

  $items['admin/esport/js'] = array(
    'type' => MENU_CALBACK,
    'page callback' => 'matches_ahah_render',
    'access callback' => TRUE,
	'file' => 'matches.list.admin.inc'
  );
  
   $items['admin/esport/matches'] = array(
    'title' => 'Matches',
    'description' => 'Set up and manage your teams results',
    'page callback' => 'matches_admin_page',
    'page arguments' => array('matches_admin'),
    'access arguments' => array('access administration pages'),
	'file' => 'matches.list.admin.inc',
    'type' => MENU_DEFAULT_LOCAL_TASK
   );  
   $items['admin/esport/matches/edit'] = array(
    'title' => 'edit',
    'page callback' => 'matches_admin_edit',
    'access arguments' => array('access administration pages'),
	'file' => 'matches.edit.admin.inc',
    'type' => MENU_CALLBACK
   );
  $items['admin/esport/tournaments'] = array(
    'title' => 'tournaments',
    'description' => 'Set up and manage your teams results',
    'page callback' => 'matches_admin_page_tournaments',
    'access arguments' => array('access administration pages'),
	'file' => 'matches.tournament.list.admin.inc',
    'type' => MENU_LOCAL_TASK
   );
  $items['admin/esport/games'] = array(
    'title' => 'games',
    'description' => 'Set up and manage your games',
    'page callback' => 'matches_admin_page_games',
    'access arguments' => array('access administration pages'),
	'file' => 'matches.games.list.admin.inc',
    'type' => MENU_LOCAL_TASK
   );
  $items['admin/esport/teams'] = array(
    'title' => 'Teams',
    'description' => 'Set up and manage your teams',
    'page callback' => 'matches_teams_admin_page',
    'access arguments' => array('access administration pages'),
	'file' => 'matches.teams.list.admin.inc',
    'type' => MENU_LOCAL_TASK
   );
  $items['matches'] = array(
    'title' => 'Matches full view',
    'page callback' => 'matches_all',
    'access arguments' => array('access matches content'),
    'type' => MENU_CALLBACK
  );
  
   $items['matches/details'] = array(
    'title' => 'Detailed match view',
    'page callback' => 'matches_details',
    'access arguments' => array('access matches content'),
    'type' => MENU_CALLBACK
  );

  return $items;
}

matches.list.admin.inc

/////////////////////////
/////////////////////////
/////MATCHES FORM/////
/////////////////////////
/////////////////////////


function matches_admin($form_state) {
  $form = array();
  
  $query = "SELECT * FROM " . "{teams_entries}";
  $query_result =  db_query($query);
  
  $query2 = "SELECT * FROM " . "{matches_tournaments}";
  $query_result2 =  db_query($query2);
  
  $form['Add_form'] = array(
    '#type' => 'fieldset',
    '#title' => t('Add a new match'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $form['Add_form']['Opponement'] = array(
    '#type' => 'fieldset',
    '#title' => t('Opponement details'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
  );
  while ($matches = db_fetch_object($query_result)) { 
  $teams_names[$matches->tid] = $matches->name;
  }
  $form['Add_form']['Opponement']['home_team'] = array(
	'#type' => 'select',
	'#title' => t('Home team'),
	'#options' => $teams_names,
	'#default_value' => $form_state['Add_form']['Opponement']['home_team'],
	'#description' => t('Select the playing team in this match.'),
	'#ahah' => array(
	  'path' => 'admin/esport/js',
	  'wrapper' => 'simple-select-wrapper',
	), 
  );
	$form['Add_form']['Opponement']['testing'] = array(
	    '#tree' => TRUE,
	    '#prefix' => '<div id="simple-select-wrapper">',
	    '#suffix' => '</div>',
	);
  $form['Add_form']['Opponement']['matches_home_lineup'] = array(
    '#type' => 'textfield',
    '#title' => t('Home team lineup'),
    '#default_value' => '',
    '#size' => 30,
    '#maxlength' => 255,
    '#description' => t("Enter the home team lineup."),
    '#required' => FALSE,
  );
  $form['Add_form']['Opponement']['matches_opponement'] = array(
    '#type' => 'textfield',
    '#title' => t('Opposite team'),
    '#default_value' => '',
    '#size' => 25,
    '#maxlength' => 255,
    '#description' => t("Enter the opposite team."),
    '#required' => TRUE,
  );
  $form['Add_form']['Opponement']['matches_opponement_lineup'] = array(
    '#type' => 'textfield',
    '#title' => t('Opposite team lineup'),
    '#default_value' => '',
    '#size' => 30,
    '#maxlength' => 255,
    '#description' => t("Enter the opposite team lineup."),
    '#required' => FALSE,
  );
  while ($tournaments = db_fetch_object($query_result2)) { 
  $tournaments_names[] = $tournaments->name;
  }
  $form['Add_form']['Opponement']['tournaments'] = array(
    '#type' => 'select',
    '#title' => t('Tournament'),
    '#options' => $tournaments_names,
    '#description' => t('Select the tournament.'),
  );
  $form['Add_form']['Opponement']['description'] = array(
    '#type' => 'textarea',
    '#title' => t('Match description'),
    '#cols' => 60,
    '#rows' => 5,
    '#description' => t('Write details about the match.'),
  );
  $form['Add_form']['Map_1'] = array(
    '#type' => 'fieldset',
    '#title' => t('Map 1'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
  );
  $form['Add_form']['Map_1']['matches_map_1_SCORE'] = array(
    '#type' => 'textfield',
    '#title' => t('Home score'),
    '#default_value' => '',
    '#size' => 15,
    '#maxlength' => 255,
    '#description' => t("Enter the home score for the first map."),
    '#required' => FALSE,
  );
  $form['Add_form']['Map_1']['matches_map_1_SCORE_VISITOR'] = array(
    '#type' => 'textfield',
    '#title' => t('Visitor score'),
    '#default_value' => '',
    '#size' => 15,
    '#maxlength' => 255,
    '#description' => t("Enter the visitor score for the first map."),
    '#required' => FALSE,
  );
  $form['Add_form']['Map_1']['matches__map_1_MAP_NAME'] = array(
    '#type' => 'textfield',
    '#title' => t('Map name'),
    '#default_value' => '',
    '#size' => 15,
    '#maxlength' => 255,
    '#description' => t("Enter the map name."),
     '#required' => FALSE,
  );
  $form['Add_form']['Map_2'] = array(
    '#type' => 'fieldset',
    '#title' => t('Map 2'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $form['Add_form']['Map_2']['matches_map_2_SCORE'] = array(
    '#type' => 'textfield',
    '#title' => t('Home score'),
    '#default_value' => '',
    '#size' => 15,
    '#maxlength' => 255,
    '#description' => t("Enter the home score for the second map."),
    '#required' => FALSE,
  );
  $form['Add_form']['Map_2']['matches_map_2_SCORE_VISITOR'] = array(
    '#type' => 'textfield',
    '#title' => t('Visitor score'),
    '#default_value' => '',
    '#size' => 15,
    '#maxlength' => 255,
    '#description' => t("Enter the visitor score for the second map."),
    '#required' => FALSE,
  );
  $form['Add_form']['Map_2']['matches__map_2_MAP_NAME'] = array(
    '#type' => 'textfield',
    '#title' => t('Map name'),
    '#default_value' => '',
    '#size' => 15,
    '#maxlength' => 255,
    '#description' => t("Enter the map name."),
     '#required' => FALSE,
  );
    $form['Add_form']['submit'] = array('#type' => 'submit', '#value' => t('Save'));
	
  if ($form_state['Add_form']['Opponement']['home_team']) {
    $form['Add_form']['Opponement']['testing'] = matches_ahah_select($form_state);
  }
  
  return $form;
}

function matches_ahah_select($form_state) {
  $sql = "SELECT mid, name FROM matches_maps WHERE gid = %d";
  
  if ($form_state['Add_form']['Opponement']['home_team']) {
    $result = db_query($sql, $form_state['Add_form']['Opponement']['home_team']);
    while (($data = db_fetch_object($result)) !== FALSE) {
      $opt[$data->mid] = $data->name;
    }
  }
  $element = array(
    '#type' => 'select',
    '#options' => $opt,
  );
  return $element;
}

function matches_ahah_render() {
  $form_state    = array('storage' => NULL, 'submitted' => FALSE);
  $form_build_id = $_POST['form_build_id'];
  
  $form    = form_get_cache($form_build_id, $form_state);
  $args    = $form['#parameters'];
  $form_id = array_shift($args);
  
  $form['#post']       = $_POST;
  $form['#redirect']   = FALSE;
  $form['#programmed'] = FALSE;
  $form_state['post']  = $_POST;
  
  // Prevents _form_builder_ie_cleanup() from incorrectly assigning the
  // first button in the form as the clicked button.
  // Wim Leers' AHAH Helper Module has more in-depth information.
  // @see the ahah_helper project
  $form_state['submitted'] = TRUE;
  
  drupal_process_form($form_id, $form, $form_state);
  
  // Once drupal_rebuild_form is called, we no longer have access to 
  // $form_state['values'], so we merge it into $form_state['storage'].
  if (isset($form_state['values'])) {
    if (!isset($form_state['storage'])) {
      $form_state['storage'] = array();
    }
    $storage = $form_state['storage'];
    $values  = $form_state['values'];
    $form_state['storage'] = array_smart_merge($storage, $values);
  }
  
  // Rebuild the form.
  $form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id);
  
  // IMPORTANT:
  // This is a simple example, and we know what the new form element is called. In a
  // real world scenario, you would need to pass a callback function to this AHAH
  // render function that would return the new content, or get the new content in
  // some other way - this is just a simple example.
  $output = $form['Add_form']['Opponement']['testing'];
  
  // Get the JS settings so we can merge them.
  $javascript = drupal_add_js(NULL, NULL, 'header');
  $settings = call_user_func_array('array_merge_recursive', $javascript['setting']);
  
  drupal_json(array(
    'status'    => TRUE,
    'data'      => theme('status_messages') . drupal_render($output),
    'settings'  => array('ahah' => $settings['ahah']),
  ));
}


/**
* Smarter version of array_merge_recursive: overwrites scalar values.
* 
* This also came (like a God send) from Wim's AHAH helper module. Really, that's the
* easiest way to go, and the module works like a charm - but I wanted to get my
* head around the whole AHAH thing, and maybe you do to, or maybe you can't or don't
* want to be dependant on a different module.
* 
* @see PHP Manual on: array-merge-recursive comment #82976.
*/





///////////////////////////////////////
///////////////////////////////////////
/////RENDERING MATCHES ADMIN/////
///////////////////////////////////////
///////////////////////////////////////
function matches_admin_page() {
$test = '';

	$head = array(
		array('data' => t('ID'), 'field' => 'mid', 'sort' => 'asc', 'width' => '30'),
		array('data' => t('Opponement'), 'width' => '30'),
		array('data' => t('Home score')),
		array('data' => t('Visitor score')),
		array('data' => t('Opérations'))
	);
 
  	$sql = "SELECT * FROM matches_entries" . tablesort_sql($head);
 
   	$result = db_query($sql);
 



  	while ($matches = db_fetch_object($result)) {
		$score_home = $matches->map_1_score_home+$matches->map_2_score_home+$matches->map_3_score_home+$matches->map_4_score_home;
		$score_visitor = $matches->map_1_score_visitor+$matches->map_2_score_visitor+$matches->map_3_score_visitor+$matches->map_4_score_visitor;
		$rows[] = array(
			array('data' => $matches->mid),
			array('data' => $matches->team),
			array('data' => $score_home),
			array('data' => $score_visitor),
			array('data' => ''.l('edit','admin/team/matches/edit/'. $matches->mid).' - '.l('delete','admin/team/matches/delete/'. $matches->mid).'')
		);
  	}
$test .= theme_table($head, $rows);

$test .= drupal_get_form('matches_admin');
  return $test;
}

function matches_admin_submit($form, &$form_state) {
  db_query("INSERT INTO {matches_entries} (mid, team) VALUES ('','%s')", $form_state['values']['matches_opponement']);
  drupal_set_message(t('Your form has been saved.') );
}

我真的很沮丧这个问题..我真的无法得到任何工作的例子,它看起来像ahah_helper不是为了我想做的...

如果有人能够让我感到高兴,我会非常感激......

蒂莫斯的照片

为什么你认为ahah_helper不能做你想要的?
我没有阅读你的所有代码,你想要做什么呢?

蒂姆巴雷特

Craz的头像

我想从另一个选择列表中填充一个选择列表,我发现有几个节点正在讨论这个但是所有的例子(包括这篇文章的一个)我试过,失败了,我不知道在哪里找到问题。我真的很感激有人看看我的代码并帮我弄清楚出了什么问题......:/

Craz的头像

在这方面,仍然没有解决问题,我真的需要让这个工作:/

nickcaballero的头像

这次真是万分感谢

_snake_的头像

谢谢,

我在找那个!

如果启用了分层选择,则会出现以下错误:

[Tue Apr 13 18:43:51 2010] [error] [client 192.168.10.50] PHP Fatal error:  Cannot redeclare array_smart_merge() (previously declared in /srv/www/htdocs/webs/nova/sites/all/modules/poof/poof.module:182) in /srv/www/htdocs/webs/nova/sites/all/modules/views/modules/hierarchical_select/hierarchical_select.module on line 2272, referer: http://192.168.100.39/
f0ns的头像

让AHAH工作的最后几天我几乎死了,我真的推荐每个想要使用AHAH检查AHAH辅助模块的人!它启发了我并添加了一个很好的演示(查看代码!!!)。

Drupedia,drupal知识库:https://www.drupedia.org

Rajan M的头像

AHAH辅助模块非常适合ahah,使用这个模块我们不需要实现所有的ahah框架,只需要注册一些辅助函数,这样可以最大限度地减少代码和复杂性。

干杯,
拉詹

Craz的头像

嗨,

你介意给我一个你如何实现它的例子吗?真的很感激:)谢谢

Rajan M的头像

我已经实现了一个示例 http://bit.ly/aTLfjV,它允许修改/设置选择框1的选项,具体取决于所选选项另一个选择框。

干杯,
拉詹

vinothbabuog的头像

嗨Rajan,
谢谢你的教程。我已在我的应用程序中实现了您的代码,在选择第一个下拉值“选项2”时,它仍为“选项1”。你能帮帮我吗?

另外,我使用内容类型创建了表单。我试图在hook_form_alter而不是hook_form中实现它。你能帮帮我吗?

Rajan M的头像

AHAH辅助模块非常适合ahah,使用这个模块我们不需要实现所有的ahah框架,只需要注册一些辅助函数,这样可以最大限度地减少代码和复杂性。

干杯,
拉詹