0

I'm trying to make a set of field type (location field type which contain of: country, City, Address, Google map which store lat & long, etc.) and this 'set' of field i need to load into my custom module (form).

so if i have:

FieldType

<?php

/**
 * @file
 * Contains \Drupal\arm_main\Plugin\Field\FieldType\CustomField.
 */

namespace Drupal\arm_main\Plugin\Field\FieldType;

use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\TypedData\DataDefinition;
use Drupal\Core\Field\FieldStorageDefinitionInterface as StorageDefinition;

/**
 * Plugin implementation of the 'custom' field type.
 *
 * @FieldType(
 *   id = "custom",
 *   label = @Translation("Custom"),
 *   description = @Translation("Stores custom data."),
 *   category = @Translation("My Category"),
 *   default_widget = "custom_default",
 *   default_formatter = "CustomFieldDefaultFormatter"
 * )
 */

class CustomField extends FieldItemBase {

  const COUNTRY_ISO2_MAXLENGTH = 2;

  public static function propertyDefinitions(StorageDefinition $storage) {

    $properties = [];

    $properties['a'] = DataDefinition::create('string')
      ->setLabel(t('Label A'))
      ->setRequired(TRUE);

    $properties['b'] = DataDefinition::create('string')
      ->setLabel(t('Label B'))
      ->setRequired(TRUE);

    $properties['c'] = DataDefinition::create('string')
      ->setLabel(t('Label C'));

    $properties['d'] = DataDefinition::create('float')
      ->setLabel(t('Label D'));

    $properties['e'] = DataDefinition::create('float')
      ->setLabel(t('Label E'));

    $properties['f'] = DataDefinition::create('integer')
      ->setLabel(t('Label F'));

    return $properties;
  }

  public static function schema(StorageDefinition $storage) {

    $columns = [];
    $columns['a'] = [
      'type' => 'varchar',
      'length' => 255,
    ];
    $columns['b'] = [
      'type' => 'varchar',
      'length' => 255,
    ];
    $columns['c'] = [
      'type' => 'text',
      'length' => 255,
    ];

    $columns['d'] = [
      'type' => 'float',
      'size' => 'big',
      'default' => 0.0,
      'not null' => FALSE,
    ];
    $columns['e'] = [
      'type' => 'float',
      'size' => 'big',
      'default' => 0.0,
      'not null' => FALSE,
    ];
    $columns['f'] = [
      'type' => 'int',
      'length' => 10,
      'not null' => FALSE,
    ];

    return [
      'columns' => $columns,
      'indexes' => [],
    ];
  }

  public function isEmpty() {

    $isEmpty = 
      empty($this->get('a')->getValue()) &&
      empty($this->get('b')->getValue()) &&
      empty($this->get('c')->getValue()) &&
      empty($this->get('d')->getValue()) &&
      empty($this->get('e')->getValue());

    return $isEmpty;
  }

  /**
   * {@inheritdoc}
   */
  public function getConstraints() {
    $constraint_manager = \Drupal::typedDataManager()->getValidationConstraintManager();
    $constraints = parent::getConstraints();

    $constraints[] = $constraint_manager->create('ComplexData', array(
      'value' => array(
        'Length' => array(
          'max' => static::COUNTRY_ISO2_MAXLENGTH,
          'maxMessage' => t('%name: the country iso-2 code may not be longer than @max characters.', array('%name' => $this->getFieldDefinition()->getLabel(), '@max' => static::COUNTRY_ISO2_MAXLENGTH)),
        )
      ),
    ));
    return $constraints;
  }

} // class

FieldWidget

<?php

/**
 * @file
 * Contains \Drupal\arm_main\Plugin\Field\FieldType\CustomFieldDefaultWidget.
 */

namespace Drupal\arm_main\Plugin\Field\FieldWidget;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;

/**
 * Plugin implementation of the 'custom_default' widget.
 *
 * @FieldWidget(
 *   id = "custom_default",
 *   label = @Translation("Custom"),
 *   field_types = {
 *     "custom"
 *   }
 * )
 */
class CustomFieldDefaultWidget extends WidgetBase {

/**
   * {@inheritdoc}
   */
  public static function defaultSettings() {
    return array(
      'size' => 60,
      'placeholder' => '',
    ) + parent::defaultSettings();
  }

  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, FormStateInterface $form_state) {
    $element['size'] = array(
      '#type' => 'number',
      '#title' => $this->t('Textfield size'),
      '#default_value' => $this->getSetting('size'),
      '#required' => TRUE,
      '#min' => 1,
    );
    $element['placeholder'] = array(
      '#type' => 'textfield',
      '#title' => t('Placeholder'),
      '#default_value' => $this->getSetting('placeholder'),
      '#description' => t('Text that will be shown inside the field until a value is entered. This hint is usually a sample value or a brief description of the expected format.'),
    );
    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsSummary() {
    $summary = array();

    $placeholder = $this->getSetting('placeholder');
    if (!empty($placeholder)) {
      $summary[] = t('Placeholder: @placeholder', array('@placeholder' => $placeholder));
    }else {
      $summary[] = t('No placeholder');
    }
    $summary[] = t('Textfield size: @size', array('@size' => $this->getSetting('size')));

    return $summary;
  }

  public function formElement(FieldItemListInterface $items, $delta, Array $element, Array &$form, FormStateInterface $formState) {

    $countries = \Drupal::service('country_manager')->getList();

    $element['a'] = [
        '#type' => 'select',
        '#options' => $countries,
        '#empty_value' => '',
        '#default_value' => (isset($items[$delta]->value) && isset($countries[$items[$delta]->value])) ? $items[$delta]->value : NULL,
        '#description' => t('Description here'),
      ];

    $element['b'] = [
      '#type' => 'textfield',
      '#title' => t('Title B'),
      '#default_value' => isset($items[$delta]->b) ? 
          $items[$delta]->b : null,
      '#empty_value' => '',
      '#placeholder' => t('B Here'),
    ];

    $element['c'] = [
      '#type' => 'textfield',
      '#title' => t('Title C'),

      '#default_value' => isset($items[$delta]->c) ? 
          $items[$delta]->c : null,

      '#empty_value' => '',
      '#placeholder' => t('C Here'),
    ];


    $element['intro'] = [
      '#type' => 'markup',
      '#markup' => t('<strong>some text here...</strong>'),
      '#prefix' => '<div>',
      '#suffix' => '</div>',
    ];

    $element['d'] = [
      '#title' => t('Title D'),
      '#type' => 'textfield',
      '#default_value' => isset($items[$delta]->d) ? $items[$delta]->d : NULL,
      '#empty_value' => 0,
      '#placeholder' => t('D Here'),
      '#attributes' => array(
        'data-d-delta' => $delta,
        'class' => array('custom-field-watch-change'),
      ),
    ];

    $element['e'] = [
      '#title' => t('Title E'),
      '#type' => 'textfield',
      '#default_value' => isset($items[$delta]->e) ? $items[$delta]->e : NULL,
      '#empty_value' => 0,
      '#placeholder' => t('E Here'),
      '#attributes' => array(
        'data-e-delta' => $delta,
        'class' => array('custom-field-watch-change'),
      ),
    ];

    $element['f'] = [
      '#title' => t('Title F'),
      '#type' => 'textfield',
      '#default_value' => isset($items[$delta]->f) ? $items[$delta]->f : NULL,
      '#empty_value' => 7,
      '#placeholder' => t('F Here'),
      '#attributes' => array(
        'data-f-delta' => $delta,
        'class' => array('custom-field-watch-change'),
      ),
    ];

    $element['open_but'] = [
      '#type' => 'button',
      '#value' => t('Set button Marker'),
      '#attributes' => array(
        'data-delta' => $delta,
        'id' => 'but_setter_' . $delta,
      ),
    ];

    $element['clear_fields'] = [
      '#type' => 'button',
      '#value' => t('Clear Fields'),
      '#attributes' => array(
        'data-delta' => $delta,
        'id' => 'clear_fields_' . $delta,
        'class' => array('custom-field-clear'),
      ),
      '#suffix' => '</div>',
    ];

    $element['preview'] = [
      '#type' => 'item',
      '#title' => t('Preview'),
      '#markup' => '<div class="custom-field-preview" data-delta="' . $delta . '"></div>',
      '#prefix' => '<div class="custom-field-widget right">',
      '#suffix' => '</div>',
    ];

    return $element;
  }

} // class

how do i load it into FormBase programmatically in here:

class testCreateForm extends FormBase {

  public function __construct($coreService, $mainService) {      }
  public static function create(ContainerInterface $container) {      }
  public function getFormId() {      }

  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['someSample'] = array(
      '#type' => 'details',
      '#title' => t('Add new things'),
      '#description' => t('desc here'),
      '#open' => TRUE,
    );
    $form['someSample']['test'] = array(
      '#type' => 'textfield',
      '#title' => t('test'),
      '#description' => $this->t('Your test code'),
      '#default_value' => "",
      '#size' => 10,
      '#maxlength' => 8,
      '#required' => TRUE,
    );
    $form['someSample']['custom'] = array( // i did this but not work
      '#type' => 'custom',
      '#title' => t('Custom Title'),
    );
    return $form;
  }

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

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

  }

}
1

The purpose of a field type is defining a field that is then attached to an entity. Once the field is attached to an entity, its widget will be used for entering the data, and its formatter will be used to show the entered data.

See for example the email field type. It's implemented by the EmailItem class; its default widget is implemented by the EmailDefaultWidget, which in £mailDefaultWidget::formElement() uses the following code.

  $element['value'] = $element + array(
    '#type' => 'email',
    '#default_value' => isset($items[$delta]->value) ? $items[$delta]->value : NULL,
    '#placeholder' => $this->getSetting('placeholder'),
    '#size' => $this->getSetting('size'),
    '#maxlength' => Email::EMAIL_MAX_LENGTH,
  );
  return $element;

With a field type, you will never directly output it in a form. That is only the purpose of its widget.

If you want to just have something to use directly in a form, you need to implement a form input element, which is what Drupal does with the Email class, for example.

As in this case, a widget class for a field type can use the form input element defined from another class.

  • Hi @kiamlaluno thanks for your reply, I did try to see your example but fail to understand how it's linked/relate all together :( i have update my question to give my complete fieldType and fieldWidget code and how i implement it. but seems like it didn't work. if you don't mind to en-light me more, very much appreciate. – AnD Jul 7 '16 at 14:35
  • You are confusing entity fields (implemented by your first part) with form fields. You don't add an entity field to a form as you are trying to do. – kiamlaluno Jul 7 '16 at 16:15
  • Thank you for the reply, to make things clearer, I'm trying to make a set of field type (location field type which contain of: country, City, Address, Google map which store lat & long, etc.) and this 'set' of field i need to load into my custom module (form). so now if I understand correctly from you: that my approach is not the right approach to my requirement, as custom field type can't be applied to a form, am I right? if, so what is the 'right' approach for this requirements? – AnD Jul 7 '16 at 16:18
0

i found some tutorial here: https://docs.acquia.com/articles/drupal-8-creating-elements-theming-elements-and-managing-frontend-libraries

and it works to me, so generally all you need to build is an element class, define your element class, apply it to template then should be done.

if someone interested, i dont mind to write more detailed here

Thanks

  • 404 error in given link. – usmanjutt84 Jun 14 at 6:33

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.