11

I tried to implement an autocomplete in text-field for drupal 8 in my custom module

all I wanted was to fetch and display the likely title I typed via autocomplete so declared a public function autocomplete within a class in DefaultController.php in folder directory -->mymodule/src/Controller/DefaultController.php

<?php

namespace Drupal\mymodule\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\JsonResponse;

class DefaultController extends ControllerBase
{
    public function autocomplete($string)
    {
        $matches = array();
        $db = \Drupal::database();
        $result = $db->select('node_field_data', 'n')
        ->fields('n', array('title', 'nid'))
        ->condition('title', '%'.db_like($string).'%', 'LIKE')
        ->addTag('node_access')
        ->execute();

        foreach ($result as $row) {
            $matches[$row->nid] = check_plain($row->title);
        }

        return new JsonResponse($matches);
    }
}

then created an EditForm.php in folder directory -->mymodule/src/Form/EditForm.php

<?php

namespace Drupal\mymodule\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class EditForm extends FormBase
{
    public function getFormId()
    {
        return 'mymodule_edit_form';
    }

    public function buildForm(array $form, FormStateInterface $form_state)
    {
        $form = array();

  $form['input_fields']['nid'] = array(
    '#type' => 'textfield',
    '#title' => t('Name of the referenced node'),
    '#autocomplete_route_name' => 'mymodule.autocomplete',
    '#description' => t('Node Add/Edit type block'),
    '#default' => ($form_state->isValueEmpty('nid')) ? null : ($form_state->getValue('nid')),
    '#required' => true,
  );

        $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Create'),
  );

        return $form;
    }
}

also created mymodule.routing.yml

  mymodule.autocomplete:
  path: '/mymodule/autocomplete'
  defaults:
    _controller: '\Drupal\mymodule\Controller\DefaultController::autocomplete'
  requirements:
    _permission: 'access content'

still autocomplete functionality not getting implemented ? Can anybody point me what am i missing ??

2
  • you need to pass parameters also drupal.org/node/2070985 Commented May 4, 2016 at 6:37
  • 1
    @ShreyaShetty No I don't need parameters since in d7 i would have used '#autocomplete_path' => 'mymodule/autocomplete', so in d8 i used '#autocomplete_route_name' => 'mymodule.autocomplete', so i never used parameter nor do i need one .... Commented May 4, 2016 at 7:07

5 Answers 5

11

Your class need some modification you need to check request and put it into $string.

<?php

namespace Drupal\mymodule\Controller;

use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Component\Utility\Unicode;

class DefaultController extends ControllerBase
{

  /**
   * Returns response for the autocompletion.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The current request object containing the search string.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   A JSON response containing the autocomplete suggestions.
   */

  public function autocomplete(request $request) {
    $matches = array();
    $string = $request->query->get('q');
    if ($string) {
      $matches = array();
      $query = \Drupal::entityQuery('node')
      ->condition('status', 1)
      ->condition('title', '%'.db_like($string).'%', 'LIKE');
      //->condition('field_tags.entity.name', 'node_access');
      $nids = $query->execute();
      $result = entity_load_multiple('node', $nids);
      foreach ($result as $row) {
        //$matches[$row->nid->value] = $row->title->value;
        $matches[] = ['value' => $row->nid->value, 'label' => $row->title->value];
      }
    }
    return new JsonResponse($matches);
  }
}
4
  • it still DID NOT WORK after fetching a request and placing it into $string Commented May 4, 2016 at 9:38
  • have you check your request was print?
    – vgoradiya
    Commented May 4, 2016 at 9:41
  • I think \Drupal::entityQuery('node') would be preferable to use apart of select.
    – vgoradiya
    Commented May 5, 2016 at 7:03
  • After watching the Network tab in my browser's dev tools, I could see proper results in the response, but they were not being shown in the UI. After some digging, I found I had some custom css setting a z-index on a DOM element which contained the form. The value was too high and was overlapping the autocomplete results. Lowering my custom z-index fixed it for me. Commented May 2, 2018 at 16:44
12

If you want to select an entity, then there is a way easier way to do that. Drupal 8 has a standard entity_autocomplete field type, just specify your form element like this:

$form['node'] = [
  '#type' => 'entity_autocomplete',
  '#target_type' => 'node',
];

See Custom autocomplete field for more information.

Also, never do database queries against node/entity tables. Use \Drupal::entityQuery() for that.

2
  • Hi Berdir, How to get data from taxanomy in my case "city" using above code as it is working perfectly fine for node but not for taxanomy??
    – Sachin
    Commented Aug 1, 2016 at 10:17
  • Thanks @Berdir, excellent answer. For term selection: $form['related'] = [ '#type' => 'entity_autocomplete', '#target_type' => 'taxonomy_term', '#selection_settings' => [ 'target_bundles' => ['topics'], ], ];
    – liquidcms
    Commented Aug 30, 2022 at 19:35
5
  1. Create a routing.yml file and add the below code : admin_example.autocomplete:

:

  path: '/admin_example/autocomplete'
  defaults:
    _controller: '\Drupal\admin_example\Controller\AdminNotesController::autocomplete'
  requirements:
    _permission: 'access content'
  1. The form which you have build in mymodule/src/Form/EditForm.php is correct

You need to change the code in controller .The code is below :

public function autocomplete(Request $request)
{
 $string = $request->query->get('q');
    $matches = array();
      $query = db_select('node_field_data', 'n')
          ->fields('n', array('title', 'nid'))
          ->condition('title', $string . '%', 'LIKE')
          ->execute()
          ->fetchAll();
    foreach ($query as $row) {
        $matches[] = array('value' => $row->nid, 'label' => $row->title);
    }

    return new JsonResponse($matches);
}
1
  • Hi Shreya, I used your solution but instead of going to the form it is giving me o/p like this: [{"value":"1","label":"Patel Residency"},{"value":"2","label":"Jain Plaza"},{"value":"3","label":"Kanha Resort"},{"value":"38","label":"Hira Residency"}]. I want it to goto the form and the field should work as autocomplete
    – Sachin
    Commented Aug 3, 2016 at 9:41
2

Use @vgoradiya code then on the foreach loop try it this way:

    foreach ($result as $row)
    {
        $matches[] = ['value' => $row->nid, 'label' => check_plain($row->title)];
    }
0

FWIW I had the same need and was greatly helped by the excellent write-up over at https://antistatique.net/en/blog/how-to-create-a-custom-autocomplete-entity-field-widget-using-the-drupal-8-form-api

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.