Jump to content

[SOLVED] enable output other than classic ajax or full admin page in "process modules" (trouble with HTMX)


Recommended Posts

Posted (edited)

When writing a process module the execute<name> methods output

  • ... either is handled as the part of content embedded in a admin page
  • ... or as output for an appropriate ajax-request (if ajax is detected while processing the incoming request by ProcessWire).

When integrating HTMX this leads to an architectural problem: output of HTMX cannot be handled inside the modules process object (which can be seen as "controller") because it is handled as content and will be embedded in an admin page layout. One has to introduce a second route and a has to create a second Controller-Object to handle especially HTMX-responses.

put on the wishlist: Processing the execute<name> methods should have something like an option to control processing the output (direct output and appropriate HTTP-headers) - not only ajax.

Edited by thei
solved
  • thei changed the title to enable output other than classic ajax or full admin page in "process modules" (trouble with HTMX)
Posted (edited)

Idk if I understand the problem, but you can just detect HTMX requests by isset($_SERVER['HTTP_HX_Request']). You could override $config->ajax with it or introduce your own $config->htmx.

Edited by Jan Romero
Posted (edited)

Hi, thanks for your response!

But: meanwhile i found out...  it's not possible

ajax handling is processed in admin.php and only there the ProcessController instance is created. This controller has its own method isAjax() and gets the result directly from the http header. But there's no way to hook in here. so one has to modify the admin.php - which i want to avoid. i simply manipulated the $ajax with the debugger and it works except that tracy debugger pollutes the response with its own stuff.

Edited by thei
Posted (edited)

The problem could be solved by modifying ProcessController->isAjax()   i.e. in  wire/core/ProcessController.php
In case of Htmx as well in case of ajax this method should return true.
More flexible: when
ProcessController would delegate this to its Process object (and the parent Process class would provide such a method by default)
than a module could override the default implementation
isAjax().  
And ... since this is no longer related to ajax only but decides between  

  •  a direct output of content  
  •  or embedding the output in a admin page

the method should be named to needsDirectOutpput() or similar.

context:  $config ->ajax is set in the ProcessWire instance by evaluating the http header HTTP_X_REQUESTED_WITH. It is used by admin.php to control an output buffer (ob_...)
inbetween $ajax is overwritten by ProcessController->isAjax().

If true the output returned by the processes execute() is not embbedded in an admin page but output directly.
In the current implementation ProcessController->isAjax() checks the http header in the same way like the ProcessWire instance.
So this has no added value in the moment. It seems this is some sort of preparation for future plans.

e.g. this works:

in ProcessController.php (delegation to Process)

public function isAjax() {
 return $this->process->isAjax();
}


in Process.php (default implementation)

public function isAjax() {
  return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest');
}

now this can be overridden by the modules class to enable htmx output

Discussion:

this is a "quick" solution.  May be there is some kind of architectural snag: the decision whether something is to be embedded in an outer frame / page would belong to the view part e.g. in a "viewFile" instead of the modules main object - which acts as a controller in this context. If - alternatively - we want to handle the mode of output controlled purely on a protocol basis we should have something like
$input->asynchProtocolType() which should return true in case of ajax, htmx and so on and should be hookable.
So this is a question to the ProcessWire Masters here...   🙂

Edited by thei
Posted (edited)

I see the problem now. It seems weird that ProcessController::isAjax() even exists, tbh. It may be vestigial and can be replaced by $config->ajax, which you could then override yourself in ready.php. But maybe it’s got some vital purpose. I’d say, open an issue about it on Github.

Some other options you can implement right now without hacking the core:

Just die()

public function ___executeCount() {
    $count = (int)$this->input->post('count');
    die($this->renderCountButton(++$count));
}

Instead of returning markup from your execute() method, just terminate the request with your desired output. This will skip things like finished.php, so that’s something to be aware of, but it’s probably fine.

 

Just add X-Requested-With

public function ___execute() {
    $this->config->scripts->add('https://cdn.jsdelivr.net/npm/htmx.org@2.0.6/dist/htmx.min.js');

    return <<<HTML
        <div hx-headers='{"X-Requested-With": "XMLHttpRequest"}'>
            <h2>Hello.</h2>
            {$this->renderCountButton(0)}
        </div>
        HTML;
}

public function ___executeCount() {
    $count = (int)$this->input->post('count');
    return $this->renderCountButton(++$count);
}

Make HTMX send the X-Requested-With header. Now you're an ajax request according to ProcessWire. The attribute is inherited, so you can just set it once and forget about it, as in the above example.

 

I have attached a complete module that minimally demonstrates the issue.

ProcessHtmxTest.module

Edited by Jan Romero
  • Like 1
Posted

Hi,

thank you for your response and your "tricky" smart ideas 🙂

With halting the process / dying i was in doubt if this would lead to some side effects. But injecting an fake HTTP header would be more save - i guess.

 

Posted
Quote

I’d say, open an issue about it on Github.

OK - i opened an issue

  • 1 month later...
  • thei changed the title to [SOLVED] enable output other than classic ajax or full admin page in "process modules" (trouble with HTMX)

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...