diff --git a/src/Control/RequestHandler.php b/src/Control/RequestHandler.php index 872c6a05b..6bee1a6b7 100644 --- a/src/Control/RequestHandler.php +++ b/src/Control/RequestHandler.php @@ -678,4 +678,15 @@ class RequestHandler extends ViewableData $url = Director::absoluteURL((string) $url); return $this->redirect($url); } + + /** + * Convert an array of data to JSON and wrap it in an HTML tag as pjax is used and jQuery will parse this + * as an element on the client side in LeftAndMain.js handleAjaxResponse() + * The attribute type="application/json" denotes this is a data block and won't be processed by a browser + * https://html.spec.whatwg.org/#the-script-element + */ + protected function prepareDataForPjax(array $data): string + { + return ''; + } } diff --git a/src/Forms/GridField/GridFieldDetailForm_ItemRequest.php b/src/Forms/GridField/GridFieldDetailForm_ItemRequest.php index 150657207..f4294dd94 100644 --- a/src/Forms/GridField/GridFieldDetailForm_ItemRequest.php +++ b/src/Forms/GridField/GridFieldDetailForm_ItemRequest.php @@ -7,6 +7,7 @@ use SilverStripe\Admin\LeftAndMain; use SilverStripe\Control\Controller; use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPResponse; +use SilverStripe\Control\PjaxResponseNegotiator; use SilverStripe\Control\RequestHandler; use SilverStripe\Core\Convert; use SilverStripe\Core\ClassInfo; @@ -170,7 +171,7 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler ])->renderWith($this->getTemplates()); if ($request->isAjax()) { - return $return; + return $this->getResponseNegotiator($return)->respond($request); } else { // If not requested by ajax, we need to render it within the controller context+template return $controller->customise([ @@ -298,6 +299,23 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler } $form->Backlink = $this->getBackLink(); + + // Ensure the correct validation response is returned for AJAX requests + $form->setValidationResponseCallback(function (ValidationResult $errors) use ($form) { + $request = $this->getRequest(); + if (!$request->isAjax()) { + return null; + } + $negotiator = $this->getResponseNegotiator($form->forTemplate()); + return $negotiator->respond($request, [ + 'ValidationResult' => function () use ($errors) { + return $this->prepareDataForPjax([ + 'isValid' => $errors->isValid(), + 'messages' => $errors->getMessages() + ]); + } + ]); + }); } $cb = $this->component->getItemEditFormCallback(); @@ -945,4 +963,36 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler } return ClassInfo::shortName($this->record); } + + /** + * Get Pjax response negotiator so form submission mirrors other form submission in the CMS. + * See LeftAndMain::getResponseNegotiator() + */ + private function getResponseNegotiator(DBHTMLText $renderedForm): PjaxResponseNegotiator + { + return new PjaxResponseNegotiator([ + 'default' => function () use ($renderedForm) { + return $renderedForm; + }, + 'Content' => function () use ($renderedForm) { + return $renderedForm; + }, + 'CurrentForm' => function () use ($renderedForm) { + return $renderedForm; + }, + 'Breadcrumbs' => function () { + return $this->renderWith([ + 'type' => 'Includes', + 'SilverStripe\\Admin\\CMSBreadcrumbs' + ]); + }, + 'ValidationResult' => function () { + // Assume valid by default, mirroring LeftAndMain's response negotiator + return $this->prepareDataForPjax([ + 'isValid' => true, + 'messages' => '', + ]); + } + ], $this->getToplevelController()->getResponse()); + } }