0

So I have created a block in which I've added a form, build with the form API. It contains a textfield and a submit button. My next step is to create a route that calls a method in a controller in my Module.

I am wondering how to do this. The form itself part of the main menu, so visible on any page. I'm not sure how to define this route. I've read there are form routes, but I don't think that's what I am looking for.

The Drupal Form API documentation says something like this:

module_search.form:
  path: '/'
  defaults:
    _title: 'Search form'
    _form: 'Drupal\module_search\Form\SearchForm'
  requirements:
    _permission: 'access content'

But I have no clue how to handle the request itself to do something with the data this form provides.

1

If you want a form in the main menu of every page, you don't need a route for it. You can just create a block, either for just the search form or for the main menu, and load the form in as a variable into that block.

namespace Drupal\module_search\Plugin\Block;

use Drupal\Core\Block\BlockBase;

/**
 * Provides a 'Header Search Block Form' block.
 *
 * @Block(
 *  id = "header_search_block",
 *  admin_label = @Translation("Header Search Form Block"),
 * )
 */
class HeaderSearchFormBlock extends BlockBase {

  /**
   * {@inheritdoc}
   */
  public function build() {

    $form = \Drupal::formBuilder()->getForm('Drupal\module_search\Form\SearchForm');
    return [
      $form,
      '#cache' => [
        'contexts' => ['url.path', 'url.query_args']
      ],
    ];
  }
}

What you're returning is a render array, so you might want caching settings on there, otherwise, you can just return the form itself. If you want to prefill the search term on every page, you'd want a cache context that includes page arguments, like above. If you want the fields empty, such as if your form only contains a textfield for searching, then you don't need a separate cached version on every page and you can just return the form in your build() function:

  public function build() {   
    return \Drupal::formBuilder()->getForm('Drupal\module_search\Form\SearchForm');    
  }

Another option, you can preprocess your main menu block to add the form as a variable as well.

function mymodule_preprocess_block__system_menu_block__header_menu(&$variables) {
  $variables['search_form'] = \Drupal::formBuilder()->getForm('Drupal\module_search\Form\SearchForm');
}

then in your block template (such as block--system-menu-block--header-menu.html.twig)

add

{{ search_form }}

As far as redirecting to search, my preferred method is with javascript, as you don't need to hit the backend. You can just redirect to your search page from the javascript.

Just attach the javascript library to your form

$form['#attached']['library'][] = 'mymodule/mymodule.header_search';

(etc. there are many tutorials on this)

and then in the javascript do something like:

 $('#' + formID).submit(function(e) {
   e.preventDefault();
   var filters = self.gatherFilters();
   var url = searchURL + '?' + $.param(filters);
   window.location.href = url;
 });

If for some reason, you need backend processing, your form can have a submitForm method that then sets the redirect on the $form_state object:

$query = ['keyword' => $search_term];    
$form_state->setRedirect($route_name, [], ['query' => $query]);

with $query being an array of query arguments.

For your search results page, I would recommend you create a different search form. As a small textfield in the header is different than filters on a form.

Without custom coding, you could use a Drupal view page, and set a contextual filter set to keyword, or you could create a controller in your custom module that returns a different search form with filters as well as the results from Elastisearch.

  • I think my question is unclear. I have created the block and the form is displaying everywhere where it should. The thing I'm struggling with is how I can catch the request when the form is submitted. I was assuming this could be done with a route, as you do in for example Laravel. There the page sends a post request, I create a route for it and I can send the data of the form into a controller. – Kevinvhengst Dec 16 '16 at 16:49
  • so when the form submits, you want it to go to a search page such as /search with a post request? or with url arguments with a $_GET request? – oknate Dec 16 '16 at 17:04
  • Well, I am implementing Elasticsearch into this application. So ye, something like /search?keyword=test I can pick up on the data the route and add use it as a parameter in my method in my search controller – Kevinvhengst Dec 16 '16 at 17:07
  • I have updated the answer. My preferred method for redirecting a search form like this is javascript attached to the form. If you're passing one parameter such as keyword, this is easy to do in javascript and this prevents having to make a backend post request. – oknate Dec 16 '16 at 17:29
  • How are you implementing Elastisearch into your Drupal? Is it a custom module, or are you using a contributed module? – oknate Dec 16 '16 at 17:39

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.