Hello Punk! This is the index #1
Create a Dynamic Modal using PHP and HTMX #0
Imam Ali Mustofa ・ Mar 26
Well, I am still at the point where I left before. Yes! The next part about:
The Head Voice!
How can I create a modal that display form to create a new supplier in my app and load the content from backend (Yes! PHP) that generate the content, also doing validation and stuff, and removing the modal after the create operation is done!.
After I create a the modal and displaying form with awesome CSS transition (copy & paste) from htmx docs. Then what I need is make that form work with insert action.
The Routing #2 POST
To make the form work with backend I need to create 1 more route that handle POST request from client to server.
<?php
// Filename: /home/darkterminal/workspaces/fck-htmx/routes/web.php
use Fckin\core\Application;
/** @var Application $app */
$app->router->get('suppliers/create', 'Suppliers@create');
$app->router->post('suppliers/create', 'Suppliers@create');
Myself: Why you don't use match routing method? Like:
$app-router->match(['GET','POST'], 'suppliers/create', 'Suppliers@create')
Aaaah... I won't! If you want, create for yourself! (btw, it's not available in my fck PHP Framework, cz I am too egoist). Don't ask about the my fck PHP Framework documentation, they doesn't exists.
The Controller #2 POST
Still in the same file, but need lil tweak! ✨
The controller before
<?php
// Filename: /home/darkterminal/workspaces/fck-htmx/controllers/Suppliers.php
namespace App\controllers;
use App\config\helpers\Utils;
use App\models\Suppliers as ModelsSuppliers;
use Fckin\core\Controller;
use Fckin\core\Request;
use Fckin\core\Response;
class Suppliers extends Controller
{
protected $suppliers;
public function __construct()
{
$response = new Response();
if (!isAuthenticate()) {
$response->setStatusCode(401);
exit();
}
$this->suppliers = new ModelsSuppliers();
}
public function create(Request $request)
{
$params = []; // <-- I will do it something here when make POST request
return Utils::addComponent('suppliers/modals/modal-create', $params);
}
}
The controller after
<?php
// Filename: /home/darkterminal/workspaces/fck-htmx/controllers/Suppliers.php
namespace App\controllers;
use App\config\helpers\Utils;
use App\models\Suppliers as ModelsSuppliers;
use Fckin\core\Controller;
use Fckin\core\Request;
use Fckin\core\Response;
class Suppliers extends Controller
{
protected $suppliers;
public function __construct()
{
$response = new Response();
if (!isAuthenticate()) {
$response->setStatusCode(401);
exit();
}
$this->suppliers = new ModelsSuppliers();
}
public function create(Request $request)
{
$params = [
'errors' => []
];
if ($request->isPost()) {
$formData = $request->getBody();
$formData['supplierCoordinate'] = empty($formData['latitude']) || empty($formData['latitude']) ? null : \implode(',', [$formData['latitude'], $formData['longitude']]);
$formData = Utils::remove_keys($formData, ['latitude', 'longitude']);
$this->suppliers->loadData($formData);
if ($this->suppliers->validate() && $this->suppliers->create($formData)) {
\header('HX-Trigger: closeModal, loadTableSupplier');
exit();
} else {
$params['errors'] = $this->suppliers->errors;
}
}
return Utils::addComponent('suppliers/modals/modal-create', $params);
}
}
Emmm.... deez neat! How the App\models\Suppliers as ModelsSuppliers look like? Did you mean the Model? Sure whatever you want! But before going further... I need to breakdown deez controller first.
$this->suppliers = new ModelsSuppliers();
Initialized the supplier model that accessible in the entire Class Controller from the __constructor method. Then I modify the $params variable
$params = [
'errors' => []
];
I add the errors key that store the error messages from validation. The validation part I will explain in the next paragraph, so the story will be inline as possible. Trust me!
if ($request->isPost())
Check if the client request to POST method, if yes then collect the payload from that request using
$formData = $request->getBody();
and store into $formData variable. Because I am handsome and stupid I create field for latitude and longitude separately and don't comment about the ternary if else statement! Pleaaaaseee....
$formData['supplierCoordinate'] = empty($formData['latitude']) || empty($formData['latitude']) ? null : \implode(',', [$formData['latitude'], $formData['longitude']]);
So I can combine the latitude and longitude as a supplierCoordinate value. Then remove the latitude and longitude from payload cz I don't need anymore.
$formData = Utils::remove_keys($formData, ['latitude', 'longitude']);
Also I load that payload into the model
$this->suppliers->loadData($formData);
So the model can read all the payload and validate the payload
$this->suppliers->validate()
In the background I have the rules for the input. They look like this:
public function rules(): array
{
return [
'supplierName' => [self::RULE_REQUIRED],
'supplierCompanyName' => [self::RULE_REQUIRED],
'supplierAddress' => [self::RULE_REQUIRED],
'supplierPhoneNumber' => [self::RULE_REQUIRED],
'supplierEmail' => [self::RULE_EMAIL],
'supplierCoordinate' => []
];
}
If validation passed! Then create the new supplier from the payload
$this->suppliers->create($formData)
If both of them is passed then send the trigger event to the client from the backend
\header('HX-Trigger: closeModal, loadTableSupplier');
