Ist es möglich, ein funktionierendes Feld-Widget-Formular alleine anzuzeigen?

21

Ich möchte ein Feld-Widget-Formular außerhalb des Kontexts des gesamten Knotenbearbeitungsformulars einbetten.

Ich habe in der Vergangenheit mit drupal_get_form vollständige Formulare angezeigt, aber dies scheint nicht für einzelne Feldformulare zu gelten.

Ist das Anzeigen eines funktionierenden Feld-Widget-Formulars möglich? Was wäre der beste Weg, dies zu tun?

Sowohl Feld-Widgets als auch "normale" Formulare scheinen sehr ähnlich zu sein. Wenn dies nicht möglich ist, was wäre erforderlich, um ein Widget-Formular in ein normales Formular umzuwandeln?

Diese Frage scheint nach etwas Ähnlichem zu fragen, aber ich verstehe die Antwort nicht. Diese Antwort gibt an, dass hook_field_widget_form_alter verwendet wird . Was ich nicht verstehe, ist, wie das Feldformular angezeigt wird und nicht, wie es angehängt wird, sobald es erstellt wird.

SMTF
quelle

Antworten:

18

VBO macht so etwas in modify.action.inc:

$form_key = 'bundle_' . $bundle_name;
$form[$form_key] = array(
  '#type' => 'fieldset',
  '#title' => $label,
  '#parents' => array($form_key),
);  
field_attach_form($context['entity_type'], $entity, $form[$form_key], $form_state, LANGUAGE_NONE);  

Sie benötigen also den Entitätstyp, die Entität (die ein leeres Objekt sein kann und nur den Bundle-Schlüsselsatz enthält, der tatsächlich verwendet wird), das Formular, in dem die Widgets hinzugefügt werden, und die Sprache. Wenn Sie die Widgets tiefer in das Formular einbetten möchten (nicht in $ form, sondern in $ form [$ form_key], wie ich es getan habe, oder sogar tiefer), muss für dieses Formulararray #parents festgelegt sein.

Beachten Sie natürlich, dass hierdurch die Widgets aller Felder eingebettet werden, die zu diesem Entitätstyp und -bündel gehören. So wurden die Attach-Funktionen geschrieben. Um das zu umgehen, müssten Sie eine Menge Code neu erfinden. Sehen Sie sich den tatsächlichen Code für das schwere Heben an. Ich gehe Feldinstanzen durch, hole jeden $ field_name und wenn mich dieser Feldtyp nicht interessiert, lege ich fest, $form[$form_key][$field_name]['#access'] = FALSE; welche Widgets nicht sichtbar sind.

EDIT: Okay, ctools hat ctools_field_invoke_field (), mit dem Sie theoretisch pro Feld arbeiten können. Ich habe es aber nie benutzt. Der obige Text ist meine direkte Erfahrung.

Bojan Zivanovic
quelle
Geniale Antwort. Ich habe den größten Teil eines Tages damit verbracht und es hat genau so funktioniert, wie ich es wollte. Kopfgeld vergeben, und ich empfehle dem OP, dies als die richtige Antwort zu akzeptieren. Am Ende habe ich einen Dummy-Inhaltstyp erstellt, damit ich meine Felder wie jeden anderen Inhaltstyp steuern kann, anstatt Einstellungen #access = FALSEvorzunehmen, die in diesem Kontext hackig erschienen.
Letharion
Vielen Dank, dass Sie bestätigt haben, was ich befürchtet hatte: dass das einzelne Feld-Widget für sich genommen praktisch nicht verwendbar ist.
SMTF
7

Ich habe die von ttk vorgeschlagene Funktion intensiv genutzt, aber ich denke, dass ein aktuelles Update die Dinge durcheinander gebracht hat ...

Hier ist eine neue Version der vorherigen Lösung, die mit Drupal 7.22 und ctools 7.x-1.3 gut funktioniert.

Also, wie im vorherigen Beitrag, rufen Sie Ihre benutzerdefinierte Funktion folgendermaßen auf:

my_field_attach_form('field_body', 'node', 'blog',  $node, $form, $form_state, LANGUAGE_NONE);

Beachten Sie, dass das Entity- Bundle jetzt ein Parameter ist. Ich habe dies getan, weil ich diese Funktion auch zum Bearbeiten von Benutzern verwendet habe. Auf diese Weise kann es auch für Taxonomiebegriffe oder andere Entitäten verwendet werden.

Und das my_field_attach_formist definiert als:

function my_field_attach_form($field_name, $entity_type, $bundle, $entity, &$form, &$form_state, $langcode = NULL) {

  // Set #parents to 'top-level' if it doesn't exist.
  $form += array('#parents' => array());

  // If no language is provided use the default site language.
  $options = array(
    'language' => field_valid_language($langcode),
    'default' => TRUE,
  );

  // Append to the form
  ctools_include('fields');
  $field_instance = field_info_instance($entity_type, $field_name, $bundle);
  $form += (array) ctools_field_invoke_field($field_instance, 'form', $entity_type, $entity, $form, $form_state, $options);
}

Diese Funktion hat mir viel Zeit gespart, hoffentlich auch für Sie!

jmcouillard
quelle
5

Hier ist die Lösung mit der ctools_field_invoke_field()Methode. Fügen Sie in Ihrer benutzerdefinierten Formularfunktion Folgendes hinzu:

$form = array();
$node = new stdClass();
$node->type = 'blog';
my_field_attach_form('field_body', 'node', $node, $form, $form_state, LANGUAGE_NONE);

wobei die my_field_attach_formFunktion definiert ist als

function my_field_attach_form($field_name, $entity_type, $entity, &$form, &$form_state, $langcode = NULL) {
  // Set #parents to 'top-level' if it doesn't exist.
  $form += array('#parents' => array());

  // If no language is provided use the default site language.
  $options = array(
    'language' => field_valid_language($langcode),
    'default' => TRUE,
  );
  module_load_include("inc","ctools","includes/fields");
  $form += (array) ctools_field_invoke_field($field_name, 'form', $entity_type, $entity, $form, $form_state, $options);
}

Beachten Sie, dass auf Ihrer Site ctools aktiviert sein muss. Es ist schade, dass Drupal standardmäßig keine solche Hilfsfunktion enthält.

ttk
quelle
2

Ich konnte die ctools-Methode nicht zum Laufen bringen und habe mich stattdessen für diese Methode entschieden.

Dieser Code würde sich innerhalb einer Formularfunktion befinden, sodass $ form und $ form_state bereits übergeben würden.

function form_function($form, &$form_state) {

Erstellen Sie zunächst einen leeren Knoten eines Typs mit dem Feld, das Sie rendern möchten.

    $entity = new stdClass();
    $entity->title = "Temp Object";
    $entity->type = "node_type";
    node_object_prepare($entity);

Ich habe die Formularvariablen dupliziert, um das Original nicht zu beschädigen.

    $temp_form       = $form;
    $temp_form_state = $form_state;
    field_attach_form("node", $entity, $temp_form, $temp_form_state);

Ziehen Sie das gesuchte Feld heraus und fügen Sie es dem Formular hinzu.

    $form["field"] = $temp_form["existing_field"];
}

Ich habe diese Methode verwendet, um das Widget "Taxonomie auswählen", das Widget "Taxonomie-Kontrollkästchen" und das Widget " Hierarchische Auswahl" in einem benutzerdefinierten Formular zu rendern . (Taxonomy Autocomplete-Widget wird gerendert, aber beim Senden wird ein Fehler ausgegeben.)

Zum Schluss rendern und drucken

drupal_render(drupal_get_form("form_function"))
Scott Joudry
quelle
Dies scheint eine einfache Möglichkeit zu sein, ein Feld-Widget in einem benutzerdefinierten Formular zu verwenden. Dies hängt jedoch von einem vorhandenen Bundle ab. In meinem Fall verwende ich einen Dummy-Inhaltstyp, in dem ich Felder nach Bedarf erstelle und konfiguriere. Das ist ein bisschen kitschig, aber auch für die anderen Methoden notwendig. Nur zur Erinnerung: Die ctools_field_invoke_field()oben beschriebene Methode funktioniert auch.
Bernhard Fürst
0

Ich habe Formulare aus einzelnen Feldern mit erstellt

field_default_form('entity_type', $entity, $field,$field_instance,LANGUAGE_NONE,$default_value, $form, $form_state);

Dies sollte das gewünschte Widget-Formular zurückgeben, das in jeder beliebigen Form verwendet werden kann

 $custom_form['form_element_to_display'] = field_default_form('entity_type', $entity, $field,$field_instance,LANGUAGE_NONE,$default_value, $custom_form, $custom_form_state);

Um die Werte für den obigen Parameter 2 zu erhalten, verwenden Sie:

$field = field_info_field($field_name);
$field_instance = field_info_instance('node', $field_name, $node_type);

Für andere Parameter können Sie den API-Link hier überprüfen

Dies gibt das Standard-Widget-Formular zurück, das im Feld Inhaltstypen definiert ist.

Hoffe das hilft jemandem :)

Akshay Daxini
quelle