Taxonomy list dependent on choice from another taxonomy list, drupal 8

别说谁变了你拦得住时间么 提交于 2019-12-24 21:21:06

问题


I have a taxonomy option list make where I choose say Toyota.

  1. I want the second taxonomy option list with the models of Toyota only (Eg. Corolla, hilux etc...).
  2. When I choose Benz the second list will then contains C-Class, ML, etc...

I have created the entity vehicle from google examples on xampp localhost, windows 10.

In my vehicle form I'm able to populate the first list. But the second appears empty.

Here is my code. Please help:

public function buildForm(array $form, FormStateInterface $form_state, $params = NULL) {
  $options = array(); 
  $tax = "make";  
  $terms = \Drupal::entityManager()->getStorage('taxonomy_term')->loadTree($tax, $parent = 0, $max_depth = NULL, $load_entities = FALSE);
  foreach ($terms as $term) {
    $options[] = $term->name;
  } 

  $form['make'] = array(
    '#type' => 'select',
    '#title' => t('Make'),
    'weight' => 0,
    '#options' => $options,
    '#ajax' => array(
      'callback' => [$this, 'changeOptionsAjax'],
      'wrapper' => 'model_wrapper',
    ),
  );

  $form['model'] = array(
    '#type' => 'select',
    '#title' => t('Model'),
    'weight' => 1,
    '#options' => $this->getOptions($form_state),
    '#prefix' => '<div id="model_wrapper">',
    '#suffix' => '</div>',
  );

  return $form;
}

public function getOptions(FormStateInterface $form_state) {
  $options = array();
  if ($form_state->getValue('make') == "Benz") { 
    $tax="benz";
  }
  elseif ($form_state->getValue('make') == "BMW") {
    $tax="bmw";
  } 
  elseif ($form_state->getValue('make') == "Toyota") {
    $tax="toyota";
  } 
  else {
    $tax="title";
    // title is just another taxonomy list I'm using as default if make is not found
  }

  $terms = \Drupal::entityManager()->getStorage('taxonomy_term')->loadTree($tax, $parent = 0, $max_depth = NULL, $load_entities = FALSE);
  foreach ($terms as $term) {
    $options[] = $term->name;
  }  
  return $options;
}

public function changeOptionsAjax(array &$form, FormStateInterface $form_state) {
  return $form['model'];
}

回答1:


Here I give you a working sample based on your example VehiculesForm.php:

I took the liberty to rename some variable for better readability.

<?php

namespace Drupal\example\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;

/**
 * VehiculesForm.
 */
class VehiculesForm extends FormBase {
  /**
   * The term Storage.
   *
   * @var \Drupal\taxonomy\TermStorageInterface
   */
  protected $termStorage;

  /**
   * {@inheritdoc}
   */
  public function __construct(EntityTypeManagerInterface $entity) {
    $this->termStorage = $entity->getStorage('taxonomy_term');
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    // Instantiates this form class.
    return new static(
    // Load the service required to construct this class.
    $container->get('entity_type.manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'vehicules_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $params = NULL) {
    $brands = $this->termStorage->loadTree('make', 0, NULL, TRUE);
    $options = [];
    if ($brands) {
      foreach ($brands as $brand) {
        $options[$brand->getName()] = $brand->getName();
      }
    }
    $form['brand'] = array(
      '#type'    => 'select',
      '#title'   => $this->t('brand'),
      '#options' => $options,
      '#ajax'    => array(
        'callback' => [$this, 'selectModelsAjax'],
        'wrapper'  => 'model_wrapper',
      ),
    );

    $form['model'] = array(
      '#type'      => 'select',
      '#title'     => $this->t('Model'),
      '#options'   => ['_none' => $this->t('- Select a brand before -')],
      '#prefix'    => '<div id="model_wrapper">',
      '#suffix'    => '</div>',
      '#validated' => TRUE,
    );

    $form['actions']['submit'] = [
      '#type'  => 'submit',
      '#value' => $this->t('Send'),
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
  }

  /**
   * Called via Ajax to populate the Model field according brand.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   *
   * @return array
   *   The form model field structure.
   */
  public function selectModelsAjax(array &$form, FormStateInterface $form_state) {
    $options = [];

    $vocabulary = 'title';
    switch ($form_state->getValue('brand')) {
      case 'Benz':
        $vocabulary = 'benz';
        break;
      case 'BMW':
        $vocabulary = 'bmw';
        break;
      case 'Toyota':
        $vocabulary = 'toyota';
        break;
    }

    $models = $this->termStorage->loadTree($vocabulary, 0, NULL, TRUE);
    if ($models) {
      foreach ($models as $model) {
        $options[$model->id()] = $model->getName();
      }
    }
    $form['model']['#options'] = $options;

    return $form['model'];
  }
}

Also, I suggest you to make some improvments on you code such:

  • Don't use a switch but link your taxonomies with a reference fields.
  • Add validation to ensure security (check we don't spoof your field for example) !!
  • Don't use the brandname but the ID. Avoid $options[$brand->getName()] = $brand->getName(); and use something like $options[$brand->id()] = $brand->getName();.

Hope it will help you !



来源:https://stackoverflow.com/questions/45785369/taxonomy-list-dependent-on-choice-from-another-taxonomy-list-drupal-8

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!