【问题标题】:Drupal 7 Form API - custom autocomplete filterDrupal 7 Form API - 自定义自动完成过滤器
【发布时间】:2014-04-16 15:25:03
【问题描述】:

使用 D7 表单 API,我需要创建一组分层过滤器,每个过滤器都依赖于前一个过滤器。当在其中一个过滤器上进行选择时,该行的所有过滤器都会根据链上的选择自动更新。看起来很简单,但还有更多。

例如,假设我有一个包含 +75k 产品记录的数据库要显示。

  • 过滤器 1 - 品牌(10k 个可能的选项)
  • 过滤器 2 - 产品(20k 个可能的选项)
  • 过滤器 3 - 名称(75k 个可能的选项)

显然我无法在每个 select-multi 中显示所有选项,所以这是我设想的工作方式:

  1. 页面加载,所有过滤器为空
  2. 每个过滤器上面都有一个小的文本输入。键入该字段会自动完成,但结果会转储到 select-multi 输入中。
  3. 用户从刚刚填充的列表中选择一个选项。
  4. 所有过滤器都会自动填充,并由链上的选择细化。

我一直在查看 D7 表单 api,但找不到任何关于此类功能的提及。我知道有 #ajax 和 #state 回调,但是文本输入自动完成填充 select-multi 和触发事件链有点模糊。

如果有帮助,我已经使用 jQuery 构建了整个功能。我现在的目标是使用适当的表单 API 将其移植到 Drupal。

【问题讨论】:

    标签: drupal


    【解决方案1】:

    我知道这已经很长时间了,但为了其他人寻找解决方案,我仍然会分享。您必须根据需要实现每个自动完成功能的自己的风格。需要注意的重要一点是使用前一个过滤器中的值设置的 autocomplete_path。休息应该是不言自明的。

    // hook_menu would look something like this
    function hook_menu() {
      $menu = array();
      $menu['hierarchical_filter'] = array(
        'title' => 'Autocomplete Ajax Cascading Form',
        'page callback' => 'drupal_get_form',
        'page arguments' => array('hierarchical_filter_form'),
        'access callback' => TRUE,
      );
      $menu['country_list'] = array(
        'title' => 'Country List autocomplete',
        'page callback' => 'country_list_autocomplete',
        'access callback' => TRUE,
        'type' => MENU_CALLBACK,
      );
      $menu['state_list'] = array(
        'title' => 'State List autocomplete',
        'page callback' => 'state_list_autocomplete',
        'access callback' => TRUE,
        'type' => MENU_CALLBACK,
      );
      $menu['city_list'] = array(
        'title' => 'City List autocomplete',
        'page callback' => 'city_list_autocomplete',
        'access callback' => TRUE,
        'type' => MENU_CALLBACK,
      );
      return $menu;
    }
    function country_list_autocomplete($string='') {
      $values = array('United States' => 'United States', 'South Africa' => 'South Africa', 'Russian Federation' => 'Russian Federation', 'Singapore' => 'Singapore', 'China' => 'China');
      $matches = array_filter($values, function($item) use($string) {
        if(stripos($item, $string) !== FALSE) return TRUE;
        return FALSE;
      });
      drupal_json_output($matches);
    }
    function state_list_autocomplete($country_code, $state='') {
      $values = array('South Africa' => array('Mpumalanga' => 'Mpumalanga', 'Gauteng' => 'Gauteng', 'Limpopo' => 'Limpopo', 'Northern Cape' => 'Northern Cape'),
        'United States' => array('Alabama'=>'Alabama', 'Arizona'=>'Arizona'));
      $matches = array_filter($values[$country_code], function($item) use($state) {
        if(stripos($item, $state) !== FALSE) return TRUE;
        return FALSE;
      });
      drupal_json_output($matches);
    }
    function city_list_autocomplete($state, $city='') {
      $values = array('northern cape' => array('Barkly West' => 'Barkly West', 'Campbell' => 'Campbell', 'Delportshoop' => 'Delportshoop'),
        'Alabama' => array('Butler'=>'Butler', 'Calera'=>'Calera', 'Helena'=>'Helena'));
      $matches = array_filter($values[$state], function($item) use($city) {
        if(stripos($item, $city) !== FALSE) return TRUE;
        return FALSE;
      });
      drupal_json_output($matches);
    }
    function hierarchical_filter_form($form, &$form_state) {
      $form = array();
      $form['country_list'] = array(
        '#type' => 'textfield',
        '#title' => 'Choose Country',
        '#autocomplete_path' => 'country_list',
        '#ajax' => array(
          'callback' => 'country_callback',
          'wrapper' => 'states_wrapper',
        ),
      );
      $form['state_list'] = array(
        '#type' => 'textfield',
        '#title' => 'Choose State',
        '#prefix' => '<div id="states_wrapper">',
        '#suffix' => '</div>',
      );
      if(isset($form_state['values']['country_list'])) {
        $form['state_list']['#autocomplete_path'] = 'state_list/'.$form_state['values']['country_list'];
        $form['state_list']['#ajax'] = array(
          'callback' => 'state_callback',
          'wrapper' => 'city_wrapper',
        );
      }
      $form['city_list'] = array(
        '#type' => 'textfield',
        '#title' => 'Choose City',
        '#prefix' => '<div id="city_wrapper">',
        '#suffix' => '</div>',
      );
      if(isset($form_state['values']['state_list'])) {
        $form['city_list']['#autocomplete_path'] = 'city_list/'.$form_state['values']['state_list'];
      }
      return $form;
    }
    function country_callback($form, &$form_state) {
      $commands = array();
      // On changing country, make sure state and city fields are reset
      $form['state_list']['#value'] = '';
      $form['city_list']['#value'] = '';
      $commands[] = ajax_command_replace('#states_wrapper', drupal_render($form['state_list']));
      $commands[] = ajax_command_replace('#city_wrapper', drupal_render($form['city_list']));
      return array('#type' => 'ajax', '#commands' => $commands);
    }
    function state_callback($form, &$form_state) {
      // On changing state, make sure city field is reset
      $form['city_list']['#value'] = '';
      return $form['city_list'];
    }
    

    希望这对某人有所帮助。

    【讨论】:

      【解决方案2】:

      创建一个论坛函数让我们说 my_module_filters_form 而不是使用 hook_menu 添加一个菜单回调

      function my_module_menu() {
        $items['my_module/ccallback' = array(
          // missing a menu item type (forgot the syntax)
          'callback function' => 'drupal_get_form',
          'callbsck arguments' => array('my_module_filters_form'),
          'access callback' => TRUE
        );
      }
      

      每次在 HTML 表单中进行更改时,都会对该回调进行 ajax 调用,并将 HTML 替换为您的输出。

      【讨论】:

        猜你喜欢
        • 2013-04-12
        • 2013-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-12
        • 1970-01-01
        • 1970-01-01
        • 2011-11-12
        相关资源
        最近更新 更多