I am currently loading in content (urls) in twig via fetch like so:
<button
@click="showModal = !showModal | fetch('{{ entry.url }}', {
method: 'GET',
headers: {
'X-Requested-With': 'XMLHttpRequest',
},
}).then(res => res.text()).then(text => { html = text })"
class="flex justify-center animate-grow-on-hover--small"
>
This loads into a modal as follows:
<main x-data="{showModal: false, html: ''}">
<div id="bgMask" class="absolute z-0 top-0 right-0 w-full h-full bg-black opacity-75" x-show="showModal"></div>
<div id="modal">
<div
class="fixed overflow-scroll mx-auto inset-x-0 inset-y-0 z-50 max-w-5xl bg-gray-200 md:rounded shadow-2xl"
x-show="showModal"
@click.away="showModal = false"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 transform scale-90"
x-transition:enter-end="opacity-100 transform scale-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 transform scale-100"
x-transition:leave-end="opacity-0 transform scale-90"
>
<div x-html="html"></div>
</div>
</div>
</main>
However, on clicking the next button there is a flash as the content visually changes in the modal.
This happens on each new item as it changes the html from the previous fetch to the new one.
How can I void this?
What is the best way with alpine.js?
Thoughts I had but have not been able to implement were:
setting the html back to html:'' but I can't seem to do this on the same @click.away call as I am hiding the modal too. Can't seem to set two options here.
Perhaps a better approach would be to show a loading icon or words until the html page has loaded and then display it once complete. However, my js coding skills are weak and I have no idea how to attempt this. If anyone is kind enough to help me, I think this would be the better approach?
Thanks in advance.
Hi @terryupton
It's more of a generic javascript question but you shouldn't use the | operator (bitwise OR) because it doesn't do exactly what you think it does (although you can achieve the same result as a side effect most of the time).
If you just need to execute a list of instructions, you can just write them one after the other one using ;.
<button
@click="html = 'loading...'; showModal = !showModal; fetch('{{ entry.url }}', {
method: 'GET',
headers: {
'X-Requested-With': 'XMLHttpRequest',
},
}).then(res => res.text()).then(text => { html = text })"
class="flex justify-center animate-grow-on-hover--small"
>
Thank you for this @SimoTod - it has helped me resolve what I was trying to do.
Would you recommend any alternative approaches or is what I have done a reasonable way to approach loading in pages via modals?
if you want to load unstructured html (different structure between calls), this is probably the simplest way to go.
Be aware that you are injecting html inside your page (with could potentially contains other scripts) so you need to make sure that the source is trustworthy (if you generate those pages by yourself, it's fine).
Since you are doing html injection and I don't think you'll need to parse the html variable for anything else, you probably don't want to duplicate the content of the page inside the html variable.
<main x-data="{showModal: false}">
<div x-ref="page"></div>
<button
@click="$ref.page.innerHTML = 'loading...'; showModal = !showModal; fetch('{{ entry.url }}', {
method: 'GET',
headers: {
'X-Requested-With': 'XMLHttpRequest',
},
}).then(res => res.text()).then(text => { $ref.page.innerHTML = text })"
>Click me</div>
</main>
This could also be extracted into a js component to remove a bit of noise from the html, but it depends on your personal tastes.
<main x-data="component()">
<div x-ref="page"></div>
<button @click="loadPage({{ entry.url }})">Click me</div>
</main>
<script>
function component() {
return {
showModal: false,
loadPage: function(url) {
// your logic, remember to prefix all the variable names with this
}
}
}
</script>
Closing this with thanks to @SimoTod
@terryupton I think you forgot to hit the "close" button 馃槃
Most helpful comment
Hi @terryupton
It's more of a generic javascript question but you shouldn't use the
|operator (bitwise OR) because it doesn't do exactly what you think it does (although you can achieve the same result as a side effect most of the time).If you just need to execute a list of instructions, you can just write them one after the other one using
;.