Llamadas AJAX en CTools Content Type Plugin?

10

Estoy creando un tipo de contenido de paneles CTools (es decir, lo que inserta en los paneles al agregar contenido, no un tipo de nodo) y estoy tratando de usar el #ajaxatributo de un elemento de formulario para establecer algunos valores predeterminados. Ver el código a continuación.

Todo esto está dentro de la my_module_content_type_edit_form($form, &$form_state)llamada del tipo de contenido , por cierto.

  $form['link_type'] = array(
    '#type' => 'radios',
    '#title' => t('Link Type'),
    '#ajax' => array(
      'callback' => 'my_module_set_target'
    ),
    '#default_value' => empty($conf['link_type']) ? '_blank' : $conf['link_type'],
    '#options' => array('none'=>t('No Link'), 'internal'=>t('Internal Link'), 'external'=>t('External Link'), 'document'=>t('Document Link')),
  );

Mi devolución de llamada es la siguiente.

function my_module_set_target($form, $form_state) {
  watchdog("Test", "Testing callback", array(), WATCHDOG_ALERT);
  $form['link_target']['#default_value'] = '_parent';

  return $form['link_target']['#default_value'];
}

Independientemente de si el retorno que sugiero realmente funcionaría, watchdog()ni siquiera funciona.

Sé que CTools hace algunas cosas raras con AJAX, pero no puede ser tan raro. ¿Tienes alguna idea de cómo haría lo que quiero hacer?

¡Gracias!

Alternativamente: ¿Cómo configuro un valor predeterminado basado en el valor de una opción de formulario anterior?

Descubrí cómo hacer esto, pero es un poco complicado: crea nuevos campos de formulario para cada bifurcación de dependencia. Luego puede fusionar los valores juntos hook_content_type_edit_form_submit(), usando el que corresponda al valor elegido para el componente que inicialmente bifurcó todo.

Dejo la pregunta abierta porque yo (y, francamente, cada programador con el que estoy trabajando) realmente quiero una buena forma de usar AJAX dentro de estos formularios de edición de tipo de contenido del Panel.

Actualización: Parece que tampoco puedes hacer cosas con #attached.

$form['link'][$i] = array(
  '#type' => 'fieldset',
  '#title' => t('Link #@num', array('@num' => $i)),
  '#collapsible' => TRUE,
  '#collapsed' => TRUE,
  '#attached' => array(
    'js' => array(
      'alert("Yay.");', 'inline'
    ),
  )
);
aendrew
fuente
Siendo un desarrollador de Drupal del tipo "Paneles para todo", imagino que también podría encontrar uso para esto en el futuro, así que agregué una recompensa, veamos qué sucede.
Letharion
Wow, esa recompensa vino y se fue sin siquiera un comentario (Gracias, por cierto, Letharion). ¿Es imposible lo que estoy pidiendo o algo así?
aendrew
Vale la pena señalar que he podido agregar Javascript con éxito usando ctools_add_js();o drupal_add_js();al final de hook_content_type_edit_form();. Si solo está haciendo cosas simples relacionadas con la interfaz de usuario, parece que esa podría ser la mejor opción (al menos hasta que alguien responda correctamente esta pregunta).
aendrew

Respuestas:

8

Respuesta corta: debe usar #ajax ['ruta'].

Respuesta larga:

Tener una devolución de llamada ajax no ayuda, ya que ctools crea sus formas de manera diferente afaik. La devolución de llamada realizada por system / ajax no puede encontrar la definición completa del formulario, por lo tanto, no puede encontrar un elemento para procesar la solicitud de ajax. El uso de #ajax [ruta] solo activa un elemento de menú.

Puede verificarlo usted mismo volcando el formulario cuando use #ajax [devolución de llamada]

function ajax_form_callback() {
  list($form, $form_state) = ajax_get_form();
  drupal_process_form($form['#form_id'], $form, $form_state);

Modifiqué el simplecontext_content_type_edit_form agregando el widget de autocompletado del usuario y su campo, que funcionan :)

function simplecontext_content_type_edit_form($form, &$form_state) {
  $conf = $form_state['conf'];

  $form['owner_name'] = array(
    '#type' => 'textfield',
    '#title' => t('Username'),
    '#default_value' => 'admin',
    '#autocomplete_path' => 'user/autocomplete',
    '#size' => '6',
    '#maxlength' => '60',
    '#description' => '$description',
  );

  $form['link_type'] = array(
    '#type' => 'radios',
    '#title' => t('Link Type'),
    '#ajax' => array(
      'path' => 'my_module_set_target'
    ),
    '#default_value' => empty($conf['link_type']) ? '_blank' : $conf['link_type'],
    '#options' => array('none' => t('No Link'), 'internal' => t('Internal Link'), 'external' => t('External Link'), 'document' => t('Document Link')),
  );
...

Como ahora usa la ruta #ajax, necesita agregar un elemento de menú como me gustó

<?php

function my_module_menu() {
  $items = array(
    'my_module_set_target' => array(
      'title' => 'AJAX Example',
      'page callback' => 'my_module_set_target',
      'access callback' => TRUE,
      'expanded' => TRUE,
    )
  );
  return $items;
}

function my_module_set_target() {
  drupal_json_output( array('data' => "ABC"));
}

Un truco sobre #attached [js]: el js en línea debe ser clave => valor como:

'#attached' => array(
  'js' => array(
    'alert("Yay.");' => 'inline',
  ),
),

He usado Firebug para verificar el valor resultante, no el efecto resultante. Espero que esto ayude a solucionar su problema.

Clemens Tolboom
fuente
Guau. Estoy tan emocionado de finalmente tener una respuesta a esta pregunta. Lo probaré en un momento. Gracias también por la nota sobre el bit # adjunto, eso es realmente lo que tenía inicialmente (pero lo cambié porque pensé que no podía estar bien).
aendrew el
Entonces, ¿algún éxito? Sería interesante saber antes de que termine la recompensa :)
Letharion
Espero obtener mi recompensa: p
Clemens Tolboom
Perdón por el retraso con esto, tener un poco de tiempo para que funcione: cuando intento devolver la matriz $ form, me dice que mi función de validación no está definida. Lo es, y cuando trato de volver a declararlo en mi módulo (a diferencia del archivo de complemento de tipo de contenido), me dice que lo estoy volviendo a declarar. Supongo que eso no es lo que necesito hacer, pero no puedo entender cómo estructurar drupal_json_output, por lo que genera algo que mi formulario interpretará como una respuesta significativa. ¿Alguna ayuda? Un mejor ejemplo de devolución de llamada ayudaría MUCHO. ¡Gracias!
aendrew
Me he perdido la pequeña parte de su pregunta que trata sobre el valor de retorno : return $ form ['link_target'] ['# default_value']; que intenta devolver un formulario drupal a un contexto html / javascript . Eso no funcionará. ¿Has visto algo similar a lo que quieres en la interfaz de usuario de los paneles? (Yo mismo desactivo JavaScript de vez en cuando con la interfaz de usuario de vistas solo para ver el flujo de trabajo que no es js) (edité este comentario un millón de veces ... incómodo)
Clemens Tolboom
2

Tuve un problema similar, en el que quería incluir un tipo de elemento Media en un complemento de tipo de contenido CTools, que también usa ajax para seleccionar una imagen.

Utiliza su propia configuración de 'ruta' ajax, en lugar de la configuración de 'devolución de llamada', pero al seleccionar una imagen, el formulario se reconstruyó sin el elemento multimedia por completo.

Rastreé esto al hecho de que drupal_rebuild_form no pudo encontrar ni la función de contenedor de formularios CTools, ni la función de formulario de configuración real. Así que lo arreglé agregando estas líneas de código al formulario de configuración de ctools:

function custom_module_my_content_plugin_content_type_edit_form($form, &$form_state) {

$background_image = isset($conf['background_image']) ? $conf['background_image'] : array();
  $form['background_image'] = array(
    '#title' => t('Background image'),
    '#default_value' => $background_image,
    '#type' => 'media',
    '#input' => TRUE,
    '#extended' => TRUE,
    '#tree' => TRUE,
    '#media_options' => array(),
  );

  // The two function calls below are necessary if we want to use a media
  // element type, because it causes ajax requests, which in turn call
  // drupal_form_rebuild(), and without the below includes, Drupal will
  // not be able to rebuild the form.

  // Include the CTools content type plugin file, because it provides
  // the ctools_content_configure_form_defaults() function, which is needed
  // when rebuilding the form, because of an ajax action, like selecting
  // a media element.
  ctools_form_include($form_state, 'content');

  // Include this plugin file as well, so that when the form is rebuilt, it
  // can successfully retrieve the settings form.
  ctools_form_include($form_state, 'my_content_plugin', 'custom_module', 'plugins/content_types/my_content_plugin');

}

Tal vez me falta algo obvio por qué los archivos de inclusión no se cargan, pero incluirlos me solucionó el problema manualmente.

Placinta
fuente
0

por mi parte, tuve que escribir una función de envoltura de formulario en el archivo .module e incluir el panel manualmente (donde se define el contenido del formulario original) así:

function mymodule_form($form, &$form_state) {
  // include mymodule/panes/mypane.inc
  ctools_include('mypane', 'mymodule', 'panes');
  return mymodule_form_content($form, $form_state);
}

Ahora, durante la llamada ajax, Drupal puede recuperar mi formulario para poder usar la API de formulario AJAX estándar.

Pierco
fuente