henrijs
henrijs

Reputation: 1010

drupal multiple node forms on one page

I have a view that displays several nodes. I want to place node form below each displayed node. Both node_add and drupal_get_form directly in template.php works fine, but I get forms with same form ID of NODETYPE_node_form and validation and submitting does not work as expected.

If you had to put several node forms on one page, what would be your general approach?

Progress so far...

in template.php while preprocessing node $author_profile and $content is set before.

$unique = $vars['node']->nid;

$node = new StdClass();
$node->uid = $vars['user']->uid;
$node->name = $vars['user']->name;
$node->type = 'review';
$node->language = '';
$node->title = t('Review of ') . $vars['node']->realname . t(' by ') . $vars['user']->realname . t(' on ') . $content->title;
$node->field_review_to_A[0]['nid'] = $nodeA->nid;
$node->field_review_to_B[0]['nid'] = $vars['node']->nid;
$node->field_review_to_profile[0]['nid'] = $author_profile->nid;

if(!function_exists("node_object_prepare")) {
    include_once(drupal_get_path('module', 'node') . '/node.pages.inc');
}

//$vars['A_review_form'] = drupal_get_form('review_node_form', $node);
$vars['A_review_form'] = mymodule_view($node, $unique);

in mymodule module

function mymodule_view($node, $unique) {
    if(!function_exists("node_object_prepare")) {
        include_once(drupal_get_path('module', 'node') . '/node.pages.inc');
    }
    $output = drupal_get_form('review_node_form_' . $unique, $node);
    return $output;
}

function mymodule_forms($form_id, $args) {
    $forms = array();
    if (strpos($form_id, "review_node_form_") === 0) {
        $forms[$form_id] = array('callback' => 'node_form');
    }
    return $forms;
}


function mymodule_form_alter(&$form, $form_state, $form_id) {
    if (isset($form['type']) && isset($form['#node']) && $form_id != $form['type']['#value'] .'_node_form' && $form['type']['#value'] == 'review') {
        $type = content_types($form['#node']->type);
        if (!empty($type['fields'])) {
            module_load_include('inc', 'content', 'includes/content.node_form');
            $form = array_merge($form, content_form($form, $form_state));
        }
        $form['#pre_render'][] = 'content_alter_extra_weights';
        $form['#content_extra_fields'] = $type['extra'];

        //$form['#id'] = $form_id;
        //$form['#validate'][0] = $form_id . '_validate';

        $form['title']['#type'] = 'value';
        $form['field_review_to_A']['#type'] = 'value';
        $form['field_review_to_B']['#type'] = 'value';
        $form['field_review_to_profile']['#type'] = 'value';
    }
}

Questions

My take on summarizing unclear questions...

  1. Is this good general approach for displaying multiple node forms on same page?
  2. Is it OK to copy/paste code from content modules content_form_alter function in function mymodule_form_alter? Will it not brake things if content module is updated?
  3. Should i set $form['#id']? Without it all forms has same HTML form ID of node_form, with it ID is unique, like review_node_form_254. Thing is that there is no difference of how form is submitted. Setting $form['#validate'][0] does not seem to influence things too. Maybe I should set $form[button]['#submit'][0] to something else? Now its node_form_submit.
  4. Why validation does not work even with unique form id and form validate function? If i submit last form without required field all previous forms gets particular fields red. should I make my own validation function? what level - form or field? Any tips on where to start?

Upvotes: 3

Views: 4908

Answers (3)

Gareth
Gareth

Reputation: 11

This was exceptionally useful to me.

Documentation on all the drupal APIs is so lacking - I was tearing my hair out. The crucial bit for me, that I don't think is covered anywhere else on the net:

CCK adds its fields to your form through hook_form_alter() . But it does this based on the form_id. So if the form ID is different (cause you want multiple ones on the same page), you need to replicate a bit of the CCK code to add the fields to your form regardless.

That is what this does brilliantly.

Upvotes: 1

mac
mac

Reputation: 43061

I really did not dig to the bottom of it, but it seems to me that you pretty much did all the relevant digging by yourself.

From what I understand by inspecting the code only, you are right in thinking that content_form_alter() is the show-stopper.

Maybe this is a naïve suggestion, but what about writing your own implementation of hook_form_alter() starting from the content_form_alter() code but changing the conditions that make the alteration to occur? I am thinking to something along these lines:

function modulename_form_alter(&$form, $form_state, $form_id) {
  if (isset($form['type']) && isset($form['#node']) && 
  stripos($form_id, $form['type']['#value'] .'_node_form')) {
    ...
  }
}

I did not actually test the code above, but I hope it is self-explenatory: you actually trigger the changes for a give customised type of content if MYCCKTYPE_node_form is a substring of the actual form_id (es: MYCCKTYPE_node_form_234).

Hope this helps at least a bit... Good luck! :)

EDIT: TWO MORE THINGS

  1. It just occurred to me that since your custom implementation of hook_form_alter() will live aside the CCK one, you would like to add a check to avoid the form to be modified twice something like:

    && $form_id != $form['type']['#value'] .'_node_form'

  2. The other way you might try to implement this by not using CCK but implementing you custom type programmatically (this might even be an advantage if you plan to use your module on various different sites).

Upvotes: 0

Henrik Opel
Henrik Opel

Reputation: 19441

You need to implement hook_forms() to map different ids to the same builder function.

The NODETYPE_node_form ids you mention are already an example of this mechanism, as they are all mapped to the same builder function (node_form()) within the node modules node_forms() implementation.

You can find links to more examples in the 'Parameters' explanation off the drupal_get_form() function.

Upvotes: 2

Related Questions