Context: I am trying to create a ajax request which alters the form_state when you click on a google maps marker.
I have a list with Beacons which contain a Location (latitude + longitude). These beacons can be added to a route and then can be given a name. To accomplish this is have created a custom Form which renders a fieldset like The addMoreFormExample and a map from the geolocation module in which they can search the beacons (Beacons show up as markers on the map).
Instead of a add more button, as shown in the example, i am trying to add the textfield by clicking on the marker (beacon) on the map. I can't seem to find any documentation about how to run this command by clicking on something else then the formElement.
My question is if there are any examples or documentation which describes how to do this.
I have tried to to take recreate the ajax request that was being invoked by the add more button:
$.ajax('/form/route?ajax_form=1&_wrapper_format=drupal_ajax', {
method: 'POST',
})
.done(function(data) {
console.log(data);
});But that gives me a error that the file upload size being too big.
I have added the full form to maybe better understand what i am trying to do:
<?php
namespace Drupal\soundtact_route\Form;
use Drupal\geolocation\GoogleMapsDisplayTrait;
use Drupal\Component\Utility\Html;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\node\NodeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Class EditRouteForm.
*/
class EditRouteForm extends FormBase {
use GoogleMapsDisplayTrait;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
* Entity type manager object.
*/
protected $entityTypeManager;
/**
* EditRouteForm constructor.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* Entity type manager.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.manager')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'edit_route_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, NodeInterface $route = NULL) {
// Create basic form structure.
$form['sidebar'] = [
'#type' => 'container',
];
$form['map'] = [
'#type' => 'container',
];
// Create header of sidebar.
$form['sidebar']['header'] = [
'#type' => 'item',
'#title' => $route->getTitle(),
];
$form['sidebar']['header']['back_to_overview'] = [
'#type' => 'link',
'#title' => $this->t('Back to overview'),
'#url' => Url::fromRoute('view.route_overview.page_1'),
];
$form['sidebar']['header']['notification'] = [
'#type' => 'select',
'#title' => $this->t('Notification'),
'#options' => [],
];
$form['sidebar']['header']['vibration'] = [
'#type' => 'select',
'#title' => $this->t('Vibration'),
'#options' => [],
];
// Create point reference.
$form['sidebar']['main'] = [
'#type' => 'container',
];
$points = $form_state->get('points');
if ($points === NULL) {
$point_values = $route->get('field_points')->getValue();
$points = $this->initPoints($form_state, $point_values);
}
// If the route has points render them else show no result message.
if ($points && count($points) > 0) {
$form['sidebar']['main']['points_fieldset'] = [
'#tree' => TRUE,
'#type' => 'fieldset',
'#title' => $this->t('Added points'),
'#prefix' => '<div id="points-fieldset-wrapper">',
'#suffix' => '</div>',
];
foreach ($points as $point) {
$form['sidebar']['main']['points_fieldset'][] = $this->createPoint($point);
}
}
else {
$form['sidebar']['main']['content'] = [
'#type' => 'html',
'#markup' => $this->t('No points found.'),
];
}
// Setup sidebar footer.
$form['sidebar']['footer'] = [
'#type' => 'container',
];
$form['sidebar']['footer']['button'] = [
'#type' => 'submit',
'#value' => $this->t('Save'),
];
$canvas_id = Html::getUniqueId('test');
$settings = GoogleMapsDisplayTrait::getGoogleMapDefaultSettings();
$form['main']['controls'] = [
'#type' => 'container',
'#attributes' => [
'id' => 'geocoder-controls-wrapper-' . $canvas_id,
'class' => [
'geocode-controls-wrapper',
],
],
];
$form['main']['controls']['location'] = [
'#type' => 'textfield',
'#placeholder' => $this->t('Enter a location'),
'#attributes' => [
'class' => [
'location',
'form-autocomplete',
],
],
'#theme_wrappers' => [],
];
$form['main']['controls']['search'] = [
'#type' => 'html_tag',
'#tag' => 'button',
'#attributes' => [
'class' => [
'search',
],
'title' => $this->t('Search'),
],
];
$form['main']['controls']['locate'] = [
'#type' => 'html_tag',
'#tag' => 'button',
'#attributes' => [
'class' => [
'locate',
],
'style' => 'display: none;',
'title' => $this->t('Locate'),
],
];
$form['main']['controls']['clear'] = [
'#type' => 'html_tag',
'#tag' => 'button',
'#attributes' => [
'class' => [
'clear',
'disabled',
],
'title' => $this->t('Clear'),
],
];
// Add the map container.
$form['main']['map_canvas'] = [
'#type' => 'html_tag',
'#tag' => 'div',
'#attributes' => [
'id' => $canvas_id,
'class' => ['map-canvas'],
],
'#attached' => [
'library' => ['geolocation/geolocation.widgets.googlegeocoder', 'soundtact_route/soundtact_route.map'],
'drupalSettings' => [
'soundtact_route' => [
'routeId' => $route->id(),
],
'geolocation' => [
'widgetSettings' => [
$canvas_id => [
'autoClientLocation' => TRUE,
'autoClientLocationMarker' => FALSE,
],
],
'widgetMaps' => [
$canvas_id => [
'lat' => 52,
'lng' => 5,
'settings' => $settings,
],
],
'google_map_url' => $this->getGoogleMapsApiUrl(),
],
],
],
];
return $form;
}
/**
* Initialize points in the formstate to the form can render.
*
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
* @param array $points
* Array with points.
*
* @return array
* Returns the form_state points.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function initPoints(FormStateInterface $form_state, array $points) {
$point_storage = $this->entityTypeManager->getStorage('point');
$beacon_storage = $this->entityTypeManager->getStorage('beacon_entity');
$state_points = [];
foreach ($points as $point) {
$entity = $point_storage->load($point['target_id']);
// If these are not defined they will return null
// otherwise it gives a int.
$beacon_id = $entity->get('beacon')->getValue()[0]['target_id'];
$file_id = $entity->get('audio')->getValue()[0]['target_id'];
$beacon_name = $this->t('Name unknown');
if ($beacon_id !== NULL) {
$beacon = $beacon_storage->load($beacon_id);
if ($name = $beacon->get('name')) {
$beacon_name = $name->getValue()[0]['value'];
}
}
$state_points[] = [
'beacon_name' => $beacon_name,
'beacon_id' => $beacon_id,
'file_id' => $file_id,
];
}
$form_state->set('points', $state_points);
return $state_points;
}
/**
* Add a new point to the form_state.
*
* @param array $form
* Form array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*/
public function addPoint(array &$form, FormStateInterface $form_state) {
// TODO: Get the id, name of the point you are trying to add.
$point = [
'beacon_id' => 1,
'beacon_name' => 'Placeholder beacon name',
'file_id' => NULL,
];
$form_state_points = $form_state->get('points');
$form_state_points[] = $point;
$form_state->set('points', $form_state_points);
$form_state->setRebuild();
}
/**
* Callback for ajax button.
*
* @param array $form
* Form array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* Form state.
*
* @return mixed
* Form element.
*/
public function addmoreCallback(array &$form, FormStateInterface $form_state) {
return $form['sidebar']['main']['points_fieldset'];
}
/**
* Create a render object for Points.
*
* @param array $point
* Array with points values.
*
* @return array
* Render object.
*/
protected function createPoint(array $point) {
$point_render_object = [
'#type' => 'container',
'#tree' => TRUE,
];
$point_render_object['title'] = [
'#type' => 'label',
'#title' => $point['beacon_name'],
];
$point_render_object['beacon_id'] = [
'#type' => 'hidden',
'#title' => $point['beacon_id'],
];
$point_render_object['audio'] = [
'#type' => 'managed_file',
'#title' => $this->t('Choose Audio File'),
'#upload_location' => 'public://audio/',
'#default_value' => [$point['file_id']],
'#description' => $this->t('Add a Audio file.'),
'#upload_validators' => [
'file_validate_extensions' => ['mp3 wac'],
],
];
return $point_render_object;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Display result.
foreach ($form_state->getValues() as $key => $value) {
drupal_set_message($key . ': ' . $value);
}
}
}
Comments
upload size being too big
I like to start simple ... have you increased the upload file limits on your site?
re: upload size being too big
Have not yet increased the upload file limits. But i don't think that is the case. The error about file size seems to be a pretty generic error. It only occurs when i have the query parameter ajax_form=1 in the url.
But after some googling i found that i should use Drupal.ajax instead of my own ajax and it feels like i am really close to solving the problem. The following code i am using the fake the form callback:
This returns a json array with inside the following objects:
But the problem now is that the data in the insert command returns the whole form and not what is inside the addmoreCallback.