Jump to content

Best method to render page content within a modal?


Recommended Posts

This may seem like a silly question. I want to be able to render the content of a page within a modal - for example, excluding the headers, sidebar and footer material.

I could do it as a iframe call to the page with a parameter that could hide the extra DOM stuff when set, but I was wondering if there is a more elegant way to do it. For example, maybe create a stripped down _main if I am doing markup regions and then call the page via the API and use _altmain instead of _main as the post file? Is that the recommended way?

I'm converting a site that was built in pods with wordpress and pods allows you to create automatic templates for each custom content type and when you render that content inside of something else it sortof automagically applies the template wherever it appears. I know this is something a bit different but... essentially I want the ability to display a page as it normally appears on the site, but then also be able to display say, just the title and body fields, for example, in a modal version of the same page.

Not sure if that makes any sense.

For example, I have a pricing page I'm working on that includes a lot of details, but also a simpler version that I'd like to bring up very quickly with a modal.

Granted I could totally do a bespoke modal, but I'm thinking there has to be a general practice that could be applied to any sort of page that uses markup regions.

Link to comment
Share on other sites

The unpoly looks really interesting - I will do a deep dive into that.

Just to be clear, I'm not asking how to create/populate the modal windows - I typically use uikit's built-ins for that. But in terms of the target, getting a stripped down version of the rendered page so that, say, only the <article> portion of the target DOM is included.

So I'm wondering if there is a generic rendering workflow that, say, let's you pass a page and selector string for the DOM and the render preprocesses and then gives you back just the DOM elements you are looking for. Like a 'render parts' or something. I'll have to think about it some more but do something else in the meantime. Maybe a module that can chain with the render process.

Link to comment
Share on other sites

@gornycreative, me and @fliwire are not teaching you how to do your modals. Both Unpoly and htmx are js libraries that help you (amoung other things) to extract a portion of markup that they receive from a ajax requests and paste it where you want it (in a modal). That way you do not need to alter the rendering, but can define which part of a rendered markup you need.

 

  • Like 3
  • Thanks 1
Link to comment
Share on other sites

7 minutes ago, gornycreative said:

Okay... yeah I looked at htmx again and I think hx-select will do what I want. Thanks!

HTMX is quite good.  $config->ajax won't detect HTMX requests though, so I recommend adding this to your /site/ready.php:

// if htmx request, DO NOT use _main.php
if(array_key_exists('HTTP_HX_REQUEST', $_SERVER)) {
  $config->appendTemplateFile = '';
  $config->htmxRequest = true;
}

That assumes you are using the Markup Regions output strategy by the way.

Use $config->htmxRequest as needed.

  • Like 5
  • Thanks 1
Link to comment
Share on other sites

This is all great stuff - the potential this has for helping do specialized streamlined DOMs to pass through to mPDF seems really big - always been one of the big pains for folks who want PDF output available.

Link to comment
Share on other sites

You can add a get parameter to the url on the ajax request, and strip the header and footer based with that (ex: ?content=modal), like you mentioned for the iframe. It solves the problem easily, and I don't think it's not elegant, just explicit.

Link to comment
Share on other sites

Posted (edited)

 

@Jonathan Lahijani's strategy is quite good. Here are a few more HTMX + $config->ajax options:

1. hx-headers (docs).

Quick and dirty addition of X-Requested-With: XMLHttpRequest to the headers. As per the docs, make sure to use the valid JSON option AND NOT the JavaScript eval().

Example:

<?php namespace ProcessWire;

// define variables
$someURL = '/some-url/';
$XMLHttpRequestJSON = json_encode(["X-Requested-With" => "XMLHttpRequest"]);
$out = "<div hx-get='{$someURL}' hx-headers='{$XMLHttpRequestJSON}'>Get Some HTML</div>";
// use $out...

The disadvantage here is having to add the headers manually to all the markup that need it. I think it could be added to body but from what I recall, there are disadvantages to adding attributes to the body tag? Maybe someone could confirm/disapprove this. Yes. hx-headers can be added to the body tag. 

Edit: From the docs...

hx-headers is inherited and can be placed on a parent element. A child declaration of a header overrides a parent declaration.

2. The ajax-header Extension (docs)

Here you will need to include the tiny (7 lines of code) extension ajax-header.js script to your HTML. You can then issue ajax requests as usual like shown below using the hx-ext attribute.

<?php namespace ProcessWire;

// define variables
$someURL = '/some-url/';
$out = "<div hx-get='{$someURL}' hx-ext='ajax-header'>Get Some HTML</div>";
// use $out...

3. htmx:configRequest (docs)

Use JavaScript to configure the request. This one is a bit more involved but gives you greater control than #2.

In this example, we assume you have a main.js file that you include in your template(s) file(s). Inside main.js, add the code as shown below.

// main.js
// DOM ready
document.addEventListener("DOMContentLoaded", function (event) {
	// init htmx with X-Requested-With
	initHTMXXRequestedWithXMLHttpRequest();
});

function initHTMXXRequestedWithXMLHttpRequest() {
	document.body.addEventListener("htmx:configRequest", (event) => {
		// if you wish to add CSRF checks. here token added to headers
		// but you can also add to request using hx-vals, for example.
		// const csrf_token = getCSRFToken();
		// event.detail.headers[csrf_token.name] = csrf_token.value;
		// add XMLHttpRequest to header to work with $config->ajax
		event.detail.headers["X-Requested-With"] = "XMLHttpRequest";
	});
}

function getCSRFToken() {
	// find element, e.g. hidden input, with id '#_post_token'
    // it holds our token name and value
	const tokenInput = htmx.find("#_post_token");
	return tokenInput;
}

 

Then in your template file:

<?php namespace ProcessWire;

// define variables
$someURL = '/some-url/';
$out = "<div hx-get='{$someURL}'>Get Some HTML</div>";
// use $out...

 

Edited by kongondo
Link to comment
Share on other sites

@kongondo Yeah I read through the docs and put things through their paces over the weekend. It's a slick lib - there are lots of places where it would be a quick way to bring together diverse apps/services output.

On 7/3/2021 at 4:10 PM, diogo said:

You can add a get parameter to the url on the ajax request, and strip the header and footer based with that (ex: ?content=modal), like you mentioned for the iframe. It solves the problem easily, and I don't think it's not elegant, just explicit.

That's true - I guess I was interested in a variety of approaches from different people.

Link to comment
Share on other sites

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
 Share

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...