Forms API - несколько кнопок submit.

Главные вкладки

Аватар пользователя CynicusAE CynicusAE 15 марта 2010 в 9:12

Доброго времени суток.

Делаю форму вида
[набор полей]
  [набор полей 1]
    [поле-1-1]
    [поле-1-2]
    [сабмит-1]
  [набор полей 2]
    [поле-2-1]
    [поле-2-2]
    [сабмит-2]

Функция построения формы (без "лишних" полей, чтобы не было избыточности информации):

function list_of_vacancies(){

// Создаем набор полей - обертку, чтобы держать информацию свернутой

    $form['vacancies_list'] = array (
        '#title' => t('List of vacancies'),
        '#type' => 'fieldset',
        '#collapsible' => TRUE,
        '#collapsed' => TRUE,
        '#tree' => TRUE,
    );
    $result = db_query ("SELECT * FROM {vacancy} WHERE companyid = %d", arg(1));

//Здесь начинаем строить наборы полей с содержимым и кнопками

    while ($item = db_fetch_object($result)){
        $form['vacancies_list'][$item->fcid] = array (
            '#type' => 'fieldset',
            '#collapsible' => FALSE,
        );
        $form['vacancies_list'][$item->fcid]['vacancy'] = array (
            '#type' => 'textfield',
            '#default_value' => $item->vacancyname,
            '#size' => 20,
        );
        $form['vacancies_list'][$item->fcid]['salary'] = array (
            '#type' => 'textfield',
            '#default_value' => $item->salary,
            '#size' => 6,
        );
        $form['vacancies_list'][$item->fcid]['update'] = array (
            '#type' => 'submit',
            '#value' => t('Update'),
            '#validate' => array ('list_of_vacancy_update_validate'),
            '#submit' => array ('list_of_vacancy_update_submit'),
        );
        $form['vacancies_list'][$item->fcid]['delete'] = array (
            '#type' => 'submit',
            '#value' => t('Delete'),
            '#submit' => array ('list_of_vacancy_delete_submit'),
        );
    }

// Общие для всех форм кнопки обработки.

    $form['vacancies_list']['update_all'] = array (
        '#type' => 'submit',
        '#value' => t('Update all')
    );
    $form['vacancies_list']['delete_all'] = array (
        '#type' => 'submit',
        '#value' => t('Delete all')
    );
    return $form;
};

В итоге получается, что на каждый набор полей вызывается одна и та же функция и обрабатывает все одноименные поля сразу. Как сообщить функциям валидации и отправки, какая именно кнопка была нажата?

Или есть иной способ получить требуемый результат? Только от подобной структуры наборов полей отказываться не хочется, потому что таких групп на одной странице может быть несколько.

Комментарии

Аватар пользователя CynicusAE CynicusAE 15 марта 2010 в 10:35

Nikit wrote:
http://drupal.org/node/144132#buttons[/quote]
Не то. Более того, оное мной благополучно используется в этом же коде. Сложность в том, что количество наборов полей переменное и зависит от числа записей в базе - одно, пять, двадцать...

Выводятся они через цикл и в данном случае и '#value' => t('something') у них будут одинаковыми, и функция обработки одна и та же. Различия только в ID - ибо ['vacancies_list'][$item->fcid]['update'] (ну и удалением аналогично).

Так что вопрос остается - как сообщить функциям валидации и отправки, какая из кнопок нажата? Выбор не между update и delete, это легко решаемо, а между разными update и разными delete.

Аватар пользователя graker graker 15 марта 2010 в 10:44

Решал аналогичную задачу. Надо в кнопке сохранять какой-нибудь id, а потом при сабмите проверять. Точно не помню где он будет доступен, что-то вроде $form_state['submit'].

На орге об этом есть информация, поищите. Если не найдете, могу примерно после 15:00 посмотреть свой код.

Аватар пользователя graker graker 15 марта 2010 в 11:41

RxB wrote:
hook_forms()? Не?

Да не, он же вроде одну форму генерирует, а не несколько форм с одним набором обработчиков.

Там не нужны никакие дополнительные поля, селекты и баттоны, надо id набора полей сохранять в массиве-описании соответствующей кнопки, он будет передан в форм-стейт, надо только вспомнить, куда именно Smile

Аватар пользователя graker graker 15 марта 2010 в 11:45

Во, нашел.

Quote:

form_state['clicked_button']
A full copy of the button element that was clicked to submit the form. This is more reliable than the old $form_values['op'] name, and also carries any additional information that was placed in the button element's form definition.

Это с той же страницы, что Nikit в начале привел. По-моему так оно и делается. После обеда проверю.

Аватар пользователя graker graker 15 марта 2010 в 11:58

Ага, я так и написал: надо id набора полей сохранять в массиве-описании соответствующей кнопки. $item->fcid из приведенного кода, вероятно, подойдет.

Но, кстати, у использования hook_forms() и генерации множества одинаковых форм есть свои плюсы. Например, легко потом повесить аякс на сабмит каждой формы. Ну и движку не нужно будет тащить в form_state значения всех групп полей при сабмите только одной группы.

Аватар пользователя Обухов Никита Обухов Никита 15 марта 2010 в 15:05

Обычно это делается так:

<?php  $form['buttons'] = array();
  
$form['buttons']['submit'] = array(
    
'#type' => 'submit',
    
'#value' => t('Save'),
    
'#weight' => 5,
    
'#validate' => array('validate_func_1'),
    
'#submit' => array('submit_func_1'),
  );
  
$form['buttons']['delete'] = array(
    
'#type' => 'submit',
    
'#value' => t('Delete'),
    
'#weight' => 15,
    
'#validate' => array('validate_func_2'),
    
'#submit' => array('submit_func_2'),
  );
?>

Ну можно конечно навесить ID и обойтись 2-мя функциями, но имхо лучше разделять.

Аватар пользователя CynicusAE CynicusAE 15 марта 2010 в 16:21

Спасибо ответившим.
Пока реализовал с помощью '#name' -> $item->fcid,в свойствах кнопки и проверки $form_state['clicked_button']['#name']в функциях.

На hook_forms() посмотрю. Похоже, это действительно будет более правильным и удобным решением.

Аватар пользователя aRpi aRpi 20 июня 2012 в 14:43

Кликнутая кнопка в *_submit доступна через:
$sta['clicked_button']

<?php
function *_submit($frm, &$sta) {
  
drupal_set_message($sta['clicked_button']['#value']);
}
?>