在DRUPAL 7自定義多行表格表單中設置添加行按鈕與刪除行按鈕
標題有點拗口,YCHEUNG也想不出來更好的中文表達,沒懂的朋友直接看內文吧(或者看url的英文標題)。
這種功能的表格表單YCHEUNG已經嘗試了五六種方式來寫,但都不滿意。不然就是功能上多少有缺陷,比如無法使用drupal 7 form API的日期type,不然就是很繁瑣的一堆代碼和判斷,看着都頭暈……等,今天終於試出了一個令YCHEUNG較滿意的寫法!分享給大家,也是一種記錄,YCHEUNG有預感,之後還會寫很多個這樣的表單QAQ
最終效果
- 效果圖一
頁面默認加載出來的表單只有一行,使用時如有需要則點擊繼續添加按鈕,操作一列因目前僅只有一行,不能作刪除操作,不顯示刪除按鈕。產品字段是自動補全的entity reference
,三個時間字段是H:i
格式用的是jQuery UI Timepicker
。
- 效果圖二
點擊繼續添加按鈕後,表格表單增加一行,並且顯示刪除按鈕。
實現步驟
- 新建一個模組module(本文中模組命名為production,此步驟略)
- 在
production.module
文件中HOOK_MENU()
/**
* Implements hook_menu().
*/
function production_menu() {
return array(
'admin/production/add' = array(
'title' => '添加表格表單',
'access arguments' => array('access administration pages'),
'type' => MENU_LOCAL_ACTION,
'page callback' => 'drupal_get_form',
'page arguments' => array('production_new_form'),
'file' => 'includes/production_admin.form.inc',
);
);
}
- 在文件
production_admin.form.inc
中先自定義一個標準的表單,$form_state['num']
表示當前表格的總行數,然後循環打印出每一行,並且當行數不止一行的時候才現實刪除行按鈕。
function production_new_form($form, &$form_state) {
if (empty($form_state['num'])) {
$form_state['num'] = 1;
}
$form = array(
'#prefix' => '<div id="addtemplate-form-wrapper">',
'#suffix' => '</div>',
);
$form['data']['und']['#tree'] = TRUE; //很重要
for ($i = 0; $i < $form_state['num']; $i++) {
$form['data']['und'][$i] = array(
'productname' => array(
'#type' => 'textfield',
'#size' => 40,
'#autocomplete_path' => 'entityreference/autocomplete/single/field_productionitemname/field_collection_item/field_productionitem/NULL',
),
'order_time' => array(
'#type' => 'textfield',
'#size' => 12,
'#attributes' => array(
'class' => ['form-text-sort', 'form-text-timefield'],
),
),
'start_time' => array(
'#type' => 'textfield',
'#size' => 12,
'#attributes' => array(
'class' => ['form-text-sort', 'form-text-timefield'],
),
),
'end_time' => array(
'#type' => 'textfield',
'#size' => 12,
'#attributes' => array(
'class' => ['form-text-sort', 'form-text-timefield'],
),
),
);
if ($form_state['num'] > 1) {
$form['data']['und'][$i]['remove_button'] = array(
'data' => array(
'#type' => 'submit',
'#value' => t('Remove'),
'#name' => 'remove-' . $i,
'#submit' => array('item_remove_one_submit'),
'#ajax' => array(
'callback' => 'item_add_and_remove_callback',
'wrapper' => 'addtemplate-form-wrapper',
),
'#limit_validation_errors' => array(),
),
);
}
}
$form['data']['actions']['add_more'] = array(
'#type' => 'submit',
'#value' => '继续添加',
'#limit_validation_errors' => array(),
'#submit' => array('item_add_more_submit'),
'#ajax' => array(
'callback' => 'item_add_and_remove_callback',
'wrapper' => 'addtemplate-form-wrapper',
'effect' => 'fade',
),
'#weight' => 10,
);
$form['actions']['save'] = array(
'#type' => 'submit',
'#value' => '保存',
'#weight' => 11,
);
$form['#attached']['js'][] = libraries_get_path('jquery.timepicker') . '/include/ui-1.10.0/jquery.ui.core.min.js';
$form['#attached']['js'][] = libraries_get_path('jquery.timepicker') . '/include/ui-1.10.0/jquery.ui.position.min.js';
$form['#attached']['js'][] = libraries_get_path('jquery.timepicker') . '/jquery.ui.timepicker.js';
$form['#attached']['js'][] = drupal_get_path('module', 'production') . '/js/timefield.js';
$form['#attached']['css'][] = libraries_get_path('jquery.timepicker') . '/jquery.ui.timepicker.css';
return $form;
}
- 將表單form轉成table的形式顯示。先
hook_theme()
在theme_production_form()
/**
* Implements hook_theme().
*/
function production_theme($existing, $type, $theme, $path) {
return array(
'production_new_form' => array(
'render element' => 'form',
),
);
}
function theme_production_new_form(&$vars) {
$form = $vars['form'];
$rows = array();
foreach (element_children($form['data']['und']) as $id) {
$rows[] = array(
'data' => array(
'productname' => drupal_render($form['data']['und'][$id]['productname']),
'order_time' => drupal_render($form['data']['und'][$id]['order_time']),
'start_time' => drupal_render($form['data']['und'][$id]['start_time']),
'end_time' => drupal_render($form['data']['und'][$id]['end_time']),
'remove_button' => drupal_render($form['data']['und'][$id]['remove_button']),
),
);
}
$header = array(
'name' => '产品',
'order_time' => '开始生产时间',
'start_time' => '开始供应时间',
'end_time' => '结束供应时间',
'remove_button' => '操作',
);
$output = theme('table', array(
'header' => $header,
'rows' => $rows,
'tree' => TRUE,
));
$output .= drupal_render_children($form);
return $output;
}
- 添加和刪除按鈕是個ajax提交,重點就在這個submit和ajax callback function里!添加一行就是把
$form_state['num']
增加一,反之就是減一。另一個關鍵是,要知道刪除的究竟是那一行的數據。所以 YCHEUNG 在刪除按鈕的name屬性上做文章,記錄當前的行順序ID,然後在提交中把這個這一行的填寫的數據unset
刪除,並且把表格表單中填寫的數據結果集重新索引排序。最後重建表單。
function item_add_and_remove_callback($form, &$form_state) {
return $form;
}
function item_add_more_submit($form, &$form_state) {
$form_state['num']++;
$form_state['rebuild'] = TRUE;
}
function item_remove_one_submit($form, &$form_state) {
$button_name = explode('-', $form_state['triggering_element']['#name']);
if ($button_name[0] == 'remove') {
$row_id = $button_name[1];
unset($form_state['input']['und'][$row_id]);
$form_state['input']['und'] = array_values($form_state['input']['und']);
}
$form_state['num']--;
$form_state['rebuild'] = TRUE;
}
這樣~就寫出了一個相對乾淨的表單啦,而且可以使用各種field type,是不是很贊呢XDDD
參考: