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 ??

  • you need to pass parameters also drupal.org/node/2070985 – Shreya Shetty May 4 '16 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 .... – make-me-alive May 4 '16 at 7:07
10

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);
  }
}
  • it still DID NOT WORK after fetching a request and placing it into $string – make-me-alive May 4 '16 at 9:38
  • have you check your request was print? – vgoradiya May 4 '16 at 9:41
  • I think \Drupal::entityQuery('node') would be preferable to use apart of select. – vgoradiya May 5 '16 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. – tyler.frankenstein May 2 '18 at 16:44
11

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.

  • 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 Aug 1 '16 at 10:17
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);
}
  • 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 Aug 3 '16 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)];
    }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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