I’m looking for a way to display validation errors in jQuery after sending a form in ajax that returns validation errors in JSON.
My code works for simple form, but the difficulties appear for more complex forms, especially for forms containing inputs for associated data.
For example :
Here is a form containing input files and associated data for writing captions :
// Articles/edit.php $this->Form->create($article); echo $this->Form->control('title'); echo $this->Form->control('photos.0.legend'); echo $this->Form->control('photos.1.legend'); $this->Form->end();
I post the form in ajax to my ArticlesController
‘s edit method that looks like that :
// ArticlesController.php public function edit($id) { $article = $this->Articles->findById($id)->firstOrFail(); if ($this->request->is(['post', 'put'])) { $article = $this->Articles->patchEntity($article, $this->request->getData()); if ($this->Articles->save($article)) { $redirection = ['action' => 'index']; if ($this->request->is('ajax')) { die(json_encode(['error' => false, 'redirection' => Router::url($redirection)])); } return $this->redirect($redirection); } else { if ($this->request->is('ajax')) { die(json_encode(['error' => true, 'validationErrors' => $article->getErrors()])); } } } $this->set(compact('article')); }
Here is the return of validation errors in JSON :
{ "error": true, "validationErrors": { "title": { "_empty": "The title please." }, "photos": { // validation errors are nested "1": { "legend": { "_empty": "The legend please." } } } } }
Here is how I’m tring to display validation errors :
// Articles/edit.php $('form') .fileupload({ // It sends the form in ajax dataType: 'json', // [...] done: function (e, data) { var responseJSON = data.jqXHR.responseJSON; if (!responseJSON.error) { // There's no error => redirect window.location = responseJSON.redirection; } else { // The form contains validation errors $.each(responseJSON.validationErrors, function (field, errors) { displayFieldErrors(field, errors); }); } }, // [...] }); // Display validation errors in a field function displayFieldErrors(field, errors) { var fieldId = field.replace(/_/, '-'); var input = $("#" + fieldId); var errorMessage = ''; $.each(errors, function (key, message) { errorMessage = errorMessage + message + '<br>'; }); input.parents('.input').addClass('error'); input.after('<div class="error-message">' + errorMessage + '</div>'); }
The problem is that validation errors for associated data fields are nested (e.g photos
), so how to get the input’s id involved ?
Could anyone help me to find a correct implementation for my jQuery function displayFieldErrors()
?
Advertisement
Answer
I’ve solved the problem by returning formated validation errors from a JSON View (server side) :
// in Articles/json/edit.php $errors = []; // Recursive function to build `$errors[]` associating each field in error to one or many error message(s) $fieldsInError = function ($err, $buildingField = '') use (&$errors, &$fieldsInError) { foreach ($err as $key => $value) { if (is_array($value)) { $fieldsInError($value, empty($buildingField) ? $key : $buildingField . '.' . $key); // recursive } else { // string if (isset($errors[$buildingField])) { if (is_array($errors[$buildingField])) { $errors[$buildingField][] = $value; } else { $errors[$buildingField] = [$errors[$buildingField], $value]; } } else { $errors += [$buildingField => $value]; } } } }; $fieldsInError($article->getErrors()); echo json_encode(['error' => true, 'validationErrors' => $errors]));
JSON is now looking like that :
{ "error": true, "validationErrors": { "title": "The title please.", "photos.1.legend": "The legend please." } }