Drupal 8: Creación de campos con Field API (Parte IV) Validación

Drupal 8: Creación de campos con Field API (Parte IV) Validación

  • Autor: fjavimartin

  • Fecha de Creación: 05/07/2017

  • Categorías:

    • Drupal,
    • Drupal 8,
    • Field,
    • Field api,
    • Validación

En nuestro anterior artículo añadimos ajax al formulario de nuestro widget, pero cuando guardamos el contenido no se guardan los datos de latitud/longitud. Aquí descubriremos como solventar este problema.

No sé si habréis llegado ya a la conclusión, pero sí, ajax no es el modo correcto de actualizar cualquier otro valor de un formulario en general. El motivo es la naturaleza de su tecnología, la ejecución del método ajax es asíncrona y se puede dar la circunstancia en la que se guarde el contenido antes de que termine de ejecutarse el método ajax haciendo imposible que se guarden los datos actualizados.

Llegados a este punto tendremos que buscar una alternativa a ajax y en esta ocasión será la inclusión de un método que nos permita validar la dirección introducida por el usuario. Solamente para el caso en el que la dirección sea correcta actualizaremos los datos de latitud/longitud.

Aunque las sugerencias del método autocomplete son muy útiles el usuario puede introducir cualquier valor en el campo dirección por lo que de esta manera validaremos los datos introducidos.

1. Modificación del formulario

Lo que haremos será incluir la propiedad #element_validate en el elemento del formulario correspondiente a la dirección. A diferencia de ajax, antes de que se guarden los valores de los campos en la base de datos siempre tendrán que ejecutarse las funciones de validación y como consecuencia, cualquier modificación de los valores del formulario en ese punto siempre se salvarán.

/**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    $key = $this->getSetting('gplaceapikey');
    $fieldclass = isset($items[$delta]) ? $items[$delta] : NULL;
    
    $element['address'] = [
        '#type' => 'textfield',
        '#title' => t('Address'),
        '#prefix' => '<div id="field-address">',
        '#suffix' => '</div>',
        '#default_value' => 
          isset($fieldclass) ? $fieldclass->get('address')->getValue() : NULL,       
        '#autocomplete_route_name' => 'address_field.autocomplete_address',
        '#autocomplete_route_parameters' => array('key' => $key),
        '#delta' => $delta,
        '#element_validate' => [ [ $this, 'validateAddress'] ],
    ];
    
    $element['latitude'] = [
        '#type' => 'textfield',
        '#title' => t('Address Latitude'),
        '#default_value' => 
          isset($fieldclass) ? $fieldclass->get('latitude')->getValue() : NULL,
    ];
    
    $element['longitude'] = [
        '#type' => 'textfield',
        '#title' => t('Address Longitude'),
        '#default_value' => 
          isset($fieldclass) ? $fieldclass->get('longitude')->getValue() : NULL,
    ];
    
    return $element;
  }

Dado que la actualización de latitud/longitud se realizará desde la función de validación podemos suprimir todo lo que configuramos en el capítulo anterior para ajax. #element_validate es un array de funciones para que desde un hook podamos incluir más funciones por lo que aquí será donde demos de alta nuestra función.

public function validateAddress($element, FormStateInterface $form_state) {
    // Capturamos dirección
    $address = $element['#value'];
    
    if (!empty($address)) {
      // Validamos la dirección
      $key = $this->getSetting('ggeocodeapikey');
      $url = 'https://maps.googleapis.com/maps/api/geocode/json?address=' . urlencode($address) . 
        '&key=' . $key;
       
      $response = file_get_contents($url);
      $json = json_decode($response);
      
      // Si la dirección es incorrecta devolvemos error en la validación
      if ($json->status != 'OK') {
        $form_state->setError($element, $this->t('Incorrect Address'));
        $latitude = 0;
        $longitude = 0;
      // Si la dirección es correcta capturamos los valores de lat/lng
      } else {
        $results = $json->results;
        $latitude = $results[0]->geometry->location->lat;
        $longitude = $results[0]->geometry->location->lng;
      }
      
      // Actualizamos los valores de lat/lng en widget
      $form_state->setValue('latitude', $latitude);
      $form_state->setValue('longitude', $longitude);
    } else if ($element['required']) {
      $form_state->setError($element, $this->t('Address empty'));
    }
  }

Con esta función reutilizamos el código de ajax y además conseguimos un doble objetivo: Por un lado validamos la dirección introducida por el usuario, que no tenía porque ser válida y por otro lado nos aseguramos que latitud/longitud siempre se guarde correctamente.

2. Conclusiones

Con este grupo de artículos hemos aprendido mucho, yo el primero. Después de recorrer 20000 foros distintos de internet buscando soluciones he intentado reunir en estos cuatro artículos soluciones a los problemas más habituales a la hora de crear un field. Espero que hayáis disfrutado leyendo estos artículos tanto como yo escribiéndolos.

Disfrutar!!!!!!

Recursos

http://www.e-quipos.es/blog/drupal-8-creaci%C3%B3n-de-campos-con-field-api

http://www.e-quipos.es/blog/drupal-8-creaci%C3%B3n-de-campos-con-field-api-parte-ii-autocomplete

http://www.e-quipos.es/blog/drupal-8-creaci%C3%B3n-de-campos-con-field-api-parte-iii-ajax

Todos los Derechos Reservados © 2016

Funciona con Drupal