Alpine Modal open on page load, but nonce closed don't open on new page loads - alpine.js

I'm having some trouble with the $persist plugin. My modal opens on page load as expected. However when I close the modal and go to another page, I don't want it to open again.
https://codepen.io/createsean/pen/MWQOvpx
codepen above shows working modal but this loads on all page loads - javascript clicks hidden button on page load.
What I want to do is have the modal show on the first page load and then subsequent page loads not show up. I think that I need to use the $persist plugin and the $store magic
However I am unable to figure out how to get this working please advise.
HTML
<div x-data="{ noticeModal: $persist(false).as('notice-modal').using(sessionStorage) }" class="flex justify-center">
<!-- Trigger -->
<span x-on:click="noticeModal = true" id="open-notice-modal" class="hidden">
<button type="button" class="bg-white px-5 py-2.5 rounded-md shadow">
Open dialog
</button>
</span>
<p class="my-12 text-2xl max-w-2xl mx-auto">A hidden button gets clicked on page load + 2 seconds and opens the modal. But it does it on every page load, when it should only be on first page load.</p>
<!-- Modal -->
<div
x-show="noticeModal"
style="display: none"
x-on:keydown.escape.prevent.stop="noticeModal = false"
role="dialog"
aria-modal="true"
x-id="['modal-title']"
:aria-labelledby="$id('modal-title')"
class="fixed inset-0 z-50 max-w-lg mx-auto overflow-y-auto"
x-transition:enter.duration.300ms
x-transition:leave.duration.200ms>
<!-- Overlay -->
<div x-show="open" x-transition.opacity class="fixed inset-0 bg-black bg-opacity-50"></div>
<!-- Panel -->
<div
x-show="open" x-transition
x-on:click="noticeModal = false"
class="relative flex items-center justify-center min-h-screen p-4">
<div
x-on:click.stop
x-trap.noscroll.inert="noticeModal"
class="relative w-full max-w-2xl p-12 overflow-y-auto bg-white shadow-lg">
<!-- Title -->
<h2 class="mt-4 mb-4 text-3xl font-bold text-center uppercase text-pinkBrand" :id="$id('modal-title')">My Title</h2>
<!-- Content -->
<div class="prose">
some copy here
</div><!-- /.prose -->
<button
type="button"
x-on:click="noticeModal = false"
class="absolute top-4 right-4">
X
</button>
</div>
</div>
</div>
</div>
javascript
// wait for dom to load then click the button that triggers the modal
document.addEventListener("DOMContentLoaded", function(event) {
let pagebutton= document.getElementById("open-notice-modal");
// load modal after 2 seconds
setTimeout(() => {
pagebutton.click();
}, "2000")
});

You should create an independent state variable in the sessionStorage that tracks only whether the modal window was opened or not. Let's call it noticeModalOpened. In the x-init attribute (so we don't have to write the extra JS), we first check noticeModalOpened state variable from the sessionStorage and enqueue an opening event only on the first page load. After the opening event we flip this state variable as well, so next time we wont open the modal again.
<div x-data="{ noticeModal: false, noticeModalOpened: $persist(false).as('notice-modal').using(sessionStorage) }"
x-init="if (!noticeModalOpened) {setTimeout(() => {noticeModal = true, noticeModalOpened = true}, 2000)}">
<!-- Trigger -->
<span #click="noticeModal = true, noticeModalOpened = true" id="open-notice-modal">
<button type="button" class="bg-white px-5 py-2.5 rounded-md shadow">
Open dialog
</button>
</span>
<!-- Modal -->
</div>

Related

How can I set a session variable conditionally in a blade template?

I am developing an app in Laravel 9 and am trying to add Cancel functionality to my Create template. I want the form to have two buttons: Submit and Cancel. I asked how to add Cancel functionality to my form last night in this question and got a couple of answers that work. However, it struck me that there might be another way to do it, namely having both buttons invoke the create() method of the controller and then for the create() method to determine which button was pushed, then do different logic based on which button was pressed. I'm imagining a session variable being set to "create" if the Create button is clicked and for the session variable to be set to "cancel" if the Cancel button is clicked.
If the Cancel button was pressed, the create() method would bypass validations and then redirect back to the index page with the message "Create() cancelled"; otherwise, if the Create button was pressed, the create() method would do all the validations, add the new record to the database, and then redirect to the index page with the message "Create was successful".
I have no concerns about getting the create() method to work but I'm having a challenge setting a session variable in my create template based on which button was pressed. I've tried several variations but all of them return "Cancel" REGARDLESS of which button was pressed! I don't understand this behaviour at all: clearly, Laravel doesn't work in the way that I imagine.
I researched how to set a session variable in a blade file here at StackOverflow but couldn't see any examples where the value of the variable was set conditionally so I clearly need some help with that part.
Here's my latest attempt at the template:
<x-layout>
<x-card xclass="p-10 max-w-lg mx-auto mt-24">
<h1 class="text-3xl text-center text-white font-bold bg-indigo-700">Create a New Non-driving Reason</h1>
<h1 class="pb-5"></h1><!-- spacer beneath title -->
<form method="POST" action="/nonDrivingReasons/store" enctype="multipart/form-data">
#csrf
<div class="mb-6">
<label for="reason_for_not_driving" class="inline-block text-lg mb-2">Reason for not driving</label>
<input type="text" class="border border-gray-200 rounded p-2 w-full" name="reason_for_not_driving" value="{{old('reason_for_not_driving')}}"/>
#error('reason_for_not_driving')
<p class="text-red-500 text-xs mt-1">{{$message}}</p>
#enderror
</div>
<div class="mb-6">
{{-- Submit the completed form --}}
<button class="text-xl text-white bg-green-500 rounded-md py-2 px-4 hover:bg-black" onClick="#php session()->put('button', 'submit') #endphp">Submit</button>
{{-- Cancel submission of the form --}}
<button class="text-xl text-white bg-black rounded-md py-2 px-4 hover:bg-red-300" onClick="#php session()->put('button', 'cancel') #endphp">Cancel</button>
</div>
</form>
</x-card>
</x-layout>
You cannot set session like this onClick="#php session()->put('button', 'submit') #endphp" because, php is server side scripting language and javascript is clientside, SO I suggest you to use little bit of js code instead of setting session,
Try using button as below:
<button class="text-xl text-white bg-green-500 rounded-md py-2 px-4 hover:bg-black" type="button">Submit</button>
{{-- Cancel submission of the form --}}
<button class="text-xl text-white bg-black rounded-md py-2 px-4 hover:bg-red-300" type="button" >Cancel</button>
</div>
And this small piece of javascript which help you to send which button you have clicked on the request:
<script>
document.querySelector("button").addEventListener("click", (e) => {
e.preventDefault()
document.getElementById("button").value = e.target.innerText;
document.querySelector('form').submit()
});
so in Controller if you do dd($request->button); you can get the value text of button that you have clicked.

AlpineJS - How to add classes on the trigger button

I am using AlpineJS and I have this HTML:
<div x-data="{ open: false }" class="flex">
<button type="button" #click="open = ! open" class="" aria-expanded="false">Women</button>
<div x-show="open" x-transition>
My hidden text
</div>
</div>
What it does is basically showing "My hidden text" when I press the button. So far so good. However I want to add classes to the button itself.
I tried this:
<button type="button" #click="open = ! open" x-transition x-transition:enter="border-indigo-600 text-indigo-600" x-transition:leave="bordertransparent text-gray-700 hover:text-gray-800" class="" aria-expanded="false">Women</button>
But this does not add the classes border-indigo-600 text-indigo-600 to the button itself.
Any idea how can I do that ?
<button ... :class="open?'classes_when_open_is_true':'classes_when_open_is_false'" ... > ... </button>

How to make parent div activate styling of child div for hover and active

I made this style for side bar navigation
I made a box and used transform to hide it on the left side, to get the curved border effect.
On hover, active ect
Border button -> bg-green-300
text-green-300 for icon and text
font-semibold for text only
<a href="/dashboard">
<div class="flex flex-row space-x-8 w-72 text-lg pb-3 text-gray-200">
<div class="h-8 w-8 rounded transform -translate-x-7 hover:bg-green-300"></div>
<div class="flex flex-row items-center space-x-8 transform -translate-x-10 -translate-y-1">
<i class="bi bi-columns-gap hover:text-green-300 transform translate-x-1"></i>
<h2 class="hover:font-semibold hover:text-green-300 transform translate-y-1 text-base">Dashboard</h2>
</div>
</div>
</a>
Is there something I can add to the main div to activate the hover effect in each child element at same time?
Right now it works only when I hover over each individual element.
Any help is much appreciated :)
Use group-hover state
Add group class to your parent element (anchor-tag in your case)
Replace hover: with group-hover:
Worth to mention not every property supports group-hover, so there can be situation, where you may need to extend core plugins. More info about group-hover here
DEMO https://play.tailwindcss.com/dzacJTR76X
Use group in parent and group:hover in child
Code Structure:
<div class="group">
<div class="group-hover:... "/>
<div class="group-hover:... "/>
</div>
Example:
<div class="group flex ">
<div class="rounded-full bg-black w-10 h-10 group-hover:bg-cyan-400 "></div>
<i class="text-4xl ml-4 group-hover:bg-cyan-400 cursor-pointer ">Brighten me</i>
</div>
Output:
OnHover:

Not able to load bootstrap modal with ajax data

I am using codeigniter to create my website. I have a dropdown menu in my first page that contains links like 'Profile', 'Edit' etc. When i click on the link (profile) it should display the bootstrap modal with corresponding user data. Used jquery to get the current id and ajax to retrieve data from database. But, when i tried to load the bootstrap modal with the response data, it displays nothing. What should i do to load the modal with ajax response data.? The response is an array containing user name, address, phone number etc.
Modal HTML
<div class="modal fade" id="MyModal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"></button>
<h4 class="modal-title">Modal Title</h4>
</div>
<div class="modal-body">
<div id="UserName"></div>
<div id="Address"></div>
<div id="Phone"></div>
</div>
<div class="modal-footer" id="buttons-box">
<button type="button" class="btn default" data-dismiss="modal">Close Modal</button>
</div>
</div>
</div>
</div>
your jQuery script
$.get('your_server_script.php', {UserId: 'UserId'}, function (response) {
$('#UserName').text(response.UserName);
$('#Address').text(response.Address);
$('#Phone').text(response.Phone);
$('#MyModal').modal('show');
});

Bootstrap twitter modal is slow to load on iPad

I'm using the standard modal popup from twitter bootstrap ui team without the fade property: http://getbootstrap.com/javascript/#modals
<div class="modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" ng-click="cancel()">×</button>
<h4 class="modal-title">Modal title</h4>
</div>
<div class="modal-body">
<ul>
<li ng-repeat="item in items">
<a ng-click="selected.item=item">{{item}}</a>
</li>
</ul>
<div>Selected Item: {{selected.item}}</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="cancel()">Close</button>
<button type="button" class="btn btn-primary" ng-click="ok()">Save changes</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- modal -->
In chrome and safari (with user-agent = ipad) it loads instantly.
On the iPad it takes more than 2.5 seconds to load. Can anyone point me to how I would start looking into this? I commented out all the css fade elements. Not sure where next to look.
Thanks
Edit: it actually works super fast on a blank page. On a page with about 50 ng-repeat elements it's super slow. My guess is that the ng-repeat elements are being redrawn when this loads? I'll investigate this.
Fixed: The problem was a dropdown in each row which caused it to render slowly. Thanks

Resources