public function ajaxSubmit()
    {
        $this->_add($cb = new jsCallback(), ['desired_name' => 'submit', 'postTrigger' => true]);

        $this->add(new View(['element' => 'input']))
            ->setAttr('name', $cb->postTrigger)
            ->setAttr('value', 'submit')
            ->setStyle(['display' => 'none']);

        $cb->set(function () {
            $caught = function ($e, $useWindow) {
                $html = '<div class="header"> '.
                        htmlspecialchars(get_class($e)).
                        ' </div> <div class="content"> '.
                        ($e instanceof \atk4\core\Exception ? $e->getHTML() : nl2br(htmlspecialchars($e->getMessage()))).
                        ' </div>';
                $this->app->terminate(json_encode(['success' => false, 'message' => $html, 'useWindow' => $useWindow]));
            };

            try {
                $this->loadPOST();
                ob_start();
                $response = $this->hook('submit');
                $output = ob_get_clean();

                if ($output) {
                    $message = new Message('Direct Output Detected');
                    $message->init();
                    $message->addClass('error');
                    $message->text->set($output);

                    return $message;
                }

                if (!$response) {
                    if (!$this->model instanceof \atk4\ui\misc\ProxyModel) {
                        $this->model->save();

                        return $this->success('Form data has been saved');
                    }

                    return new jsExpression('console.log([])', ['Form submission is not handled']);
                }
            } catch (\atk4\data\ValidationException $val) {
                $response = [];
                foreach ($val->errors as $field => $error) {
                    $response[] = $this->error($field, $error);
                }

                return $response;
            } catch (\Error $e) {
                return $caught($e, false);
            } catch (\Exception $e) {
                return $caught($e, true);
            }

            return $response;
        });

        //var_dump($cb->getURL());
        $this->js(true)
            ->api(array_merge(['url' => $cb->getJSURL(), 'method' => 'POST', 'serializeForm' => true], $this->apiConfig))
            ->form(array_merge(['inline' => true, 'on' => 'blur'], $this->formConfig));

        $this->on('change', 'input', $this->js()->form('remove prompt', new jsExpression('$(this).attr("name")')));
    }