I am trying to bind backAfterSaveStatus value to hidden input and for some reason then form is submited backAfterSave value is null.
After that I go back and submit form again - backAfterSave value is 1. Where is the problem?
I tried same thing without prevent and submit() but it's not working still. Also I had dumped div with x-text and code makes hidden input 1 before form submit. What I am doing wrong?
<form action="<...>" method="post">
<div x-data="{
backAfterSaveStatus: '',
backAfterSave () {
this.backAfterSaveStatus = '1';
document.querySelector('form.withBackAfterSave').submit();
}
}">
<input name="backAfterSave" :value="backAfterSaveStatus">
<div>
<span>
<button x-on:click.prevent="backAfterSave()" type="submit">
Save & back
</button>
</span>
<span>
<button type="submit">
Save
</button>
</span>
</div>
</div>
</form>
I want same result as below:
let buttonBackAfterSave = document.getElementById('button-back-after-save');
if (buttonBackAfterSave) {
buttonBackAfterSave.addEventListener('click', () => document.getElementById('input-back-after-save').value = 1);
}
The problem is the form being submitted "too fast" (the backAfterSaveStatus value isn't done binding to the input). Use $nextTick so Alpine waits until the value is properly changed.
<form method="post" class="withBackAfterSave">
#csrf
<div x-data="{
backAfterSaveStatus: '',
backAfterSave () {
this.backAfterSaveStatus = '1';
this.$nextTick(() => { document.querySelector('form.withBackAfterSave').submit() });
}
}">
<input name="backAfterSave" x-bind:value="backAfterSaveStatus">
<div>
<span>
<button x-on:click.prevent="backAfterSave()" type="submit">
Save & back
</button>
</span>
<span>
<button type="submit">
Save
</button>
</span>
</div>
</div>
</form>
Thank you! I don't use x-ref because these buttons are in separate layouts file, so I can't move it outside x-data range. My final code:
<div class="pt-5">
<div class="flex justify-end" x-data="{
backAfterSave: 0
}">
<input type="hidden" name="backAfterSave" :value="backAfterSave">
<button type="button"
class="bg-white py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
{{ __('Cancel') }}
</button>
<button type="submit"
#click.prevent="backAfterSave=1; $nextTick(() => {
document.querySelector('form.with-back-after-save').submit()
})"
class="ml-3 inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
{{ __('Save & back') }}
</button>
<button type="submit"
class="ml-3 inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-teal-600 hover:bg-teal-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-teal-500">
{{ __('Save') }}
</button>
</div>
</div>
Just released that I could use simple button with custom name and given value.. No javascript was needed :)
<button type="submit" name="back-after-submit" value="1">Save</button>
Related
how can I display my Invitee2 a bit upper in my gray bar ? And for my button how can I put it on the extrem right side of my gray bar ?
<div className="bg-gray-200 p-5 h-5 pl-2 mb-2 text-md text-primary-500 font-bold text-gray-500">
Invitee {i + 1}
<span className="float-right -mt-5">
{!!i && (
<Button primary className="rounded-md float-right mt-4" onClick={() => removeInvitee(pId)}>
- Invitee
</Button>
)}
</span>
And Button.jsx:
export default function Button({ onClick,primary,children,disabled }) {
return <button
onClick={onClick}
className={`${primary
? ' cursor-pointer rounded-md bg-primary-700 py-2 px-3 text-white hover:bg-blue-700 hover:text-white'
: 'bg-transparent text-gray border border-primary-500 hover:border-primary-100 hover:text-primary-100 transition duration-200 '}
text-primary-fg py-2 px-3 rounded-md transition-colors `}
disabled={disabled}
>{children}</button>
}
Here a picture to get the idea :
Add flex flex-row justify-between items-center in your div class
and remove the -mt-5 in span class beside float-right
check the code below
<div className="flex flex-row justify-between items-center bg-gray-200 p-5 h-5 pl-2 mb-2 text-md text-primary-500 font-bold text-gray-500">
Invitee {i + 1}
<span className="float-right">
{!!i && (
<Button primary className="rounded-md float-right mt-4" onClick={() => removeInvitee(pId)}>
- Invitee
</Button>
)}
</span>
</div>
You can use the flexbox properties to make the design you want. I had created the very similar example below , please add your functions here and replace class with className.
<script src="https://cdn.tailwindcss.com"></script>
<div class="container mx-auto py-4">
<div class="bg-gray-200 text-md flex items-center justify-between rounded-r-md">
<div class=" font-bold text-gray-500 ml-4" >Invitee 2</div>
<div class="">
<Button primary class="rounded-md bg-black text-white py-2 px-4" onclick="removeInvitee(pId)">
- Invitee
</Button>
</div>
</div>
</div>
trying to prevent default on form submission though it goes ahead and submits user input--
if I have the form onsubmit value to empty then the form prevents default.. is there solution to this?
Below is my form; on submit is empty as it prevents default when empty. though it should be going to generate as shown below...
<form className='grid' onSubmit={}>
<div className='flex'>
{/* <InputField
isRequired={true}
id='productNameField'
required={true}
className='border-solid border-2 border-gray-200 pl-3 w-full rounded-lg h-full'
type='text'
placeholder='Spotify'
label='Product Name'
onChange={onSetProductName}
/> */}
<div className=' relative '>
<label className='text-gray-700'>
Product Name
<span className='text-red-500 required-dot'>*</span>
</label>
<input
type='text'
required
className=' rounded-lg border-transparent flex-1 appearance-none border border-gray-400 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-accent1 focus:border-transparent'
placeholder='Spotify'
onChange={onSetProductName}
/>
</div>
</div>
{/* <div className='flex pt-6'>
<InputField
id='productDescriptionField'
required={true}
className='border-solid border-2 border-gray-200 pl-3 w-full rounded-lg resize-none h-full p-1'
type='text'
placeholder='Spotify is a music service that lets you listen to music and share it with friends.'
label='Product Description'
maxRows={5}
onChange={onSetProductDescription}
multiline
/>
</div>
<div className='flex pt-6'>
<InputField
id='platformField'
required={true}
className='border-solid border-2 border-gray-200 pl-3 w-full rounded-lg h-full'
type='text'
placeholder='Instagram'
label='Platform'
onChange={onSetPlatform}
/>
</div>
<div className='flex pt-6'>
<InputField
id='audienceField'
required={true}
className='border-solid border-2 border-gray-200 pl-3 w-full rounded-lg h-full'
type='text'
placeholder='Teens'
label='Audience'
onChange={onSetAudience}
/>
</div> */}
<div className='grid'>
<div className='grid grid-cols-2 pt-6'>
{pendingCreativeAd === true ? (
<div className='grid justify-start'>
<button
type='button'
disabled={true}
className='py-2 px-4 flex justify-center items-center bg-gray-600 text-white w-full transition ease-in duration-200 text-center text-base font-semibold rounded-lg '
>
1 sec.
<LoadingIcon height={21} width={21} />
</button>
</div>
) : (
<div className='grid justify-start'>
<button
type='submit'
// onClick={generate}
className='py-2 px-4 flex justify-center items-center bg-accent1 hover:bg-blue-800 focus:bg-accent1 text-white w-full transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none rounded-lg '
>
Generate
</button>
</div>
)}
<div className='grid justify-end'>
<button
type='button'
onClick={clearForm}
className='py-2 px-4 flex justify-center items-center bg-orange-700 hover:bg-orange-800 text-white w-full transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:bg-orange-700 rounded-lg '
>
Clear Form
</button>
</div>
</div>
</div>
</form>
const generate = async (e) => {
e.preventDefault();
startGenAd(productName, productDescription, platform, audience);
console.log('submitting generate');
};
Just use your generate function in Form's Submit Event Instead of Button's Click Event. I think this is the easiest Approach.
set type e to
const generate = async (e: { preventDefault: () => void; }) => {
e.preventDefault();
startGenAd(productName, productDescription, platform, audience);
console.log('submitting generate');
};
As my title already says, I have an issue with a modal not opening on all buttons.
Here is the situation:
I have a page that displays all applications a user has sent for different jobs. So it may be just one, or up to whatever.
It looks like this:
Now if the user wants to cancel the application he can press the button "Bewerbung zurückziehen", then the modal opens to give a heads up that all data will be lost and if he is sure, in the modal he can confirm it or go back. Everything works fine for the first post on the site, but for all other posts just nothing happens, so the modal doesn't open.
Here is my code:
The blade file that displays all posts:
#foreach($bewerbungen as $bewerbung)
#foreach($stellenanzeigen_names as $stellenanzeigen_name)
#if($bewerbung->Stellenanzeigen_ID === $stellenanzeigen_name->Stellenanzeigen_ID)
<div
class="p-10 grid-cols-3 grid-rows-3 gap-4 shadow-2xl mb-10 bg-gradient-to-r from-green-400 to-blue-500 border-solid border-2 border-black rounded-lg">
<!--Card 1-->
<div
class="overflow-hidden row-span-3 bg-gray-100 shadow-2xl border-solid border-2 border-gray-500 rounded-lg">
<div class="pt-4 pl-4">
{{ $stellenanzeigen_name->Titel }}
<hr class="border-black">
</div>
<div class="pt-4 pl-8 font-medium text-xl font-bold font-serif">
ID der Bewerbung: {{ $bewerbung->Bewerbung_ID }}</div>
<div class="pt-4 pl-8 pb-3 font-medium text-xl font-bold font-serif">
ID der Stellenanzeige: {{ $bewerbung->Stellenanzeigen_ID }}</div>
<div class="w-1/4 mb-4 pl-4">
<div class="font-medium text-base font-bold font-serif mb-4 pb-3">
<button type="submit" id="delete_appl_btn" name="delete_appl_btn"
class="mb-4 pb-3 w-full text-white px-4 py-3 rounded text-base font-medium
bg-gradient-to-r from-green-400 to-blue-500 float-right shadow transition
duration-500 ease-in-out transform hover:-translate-y-1 hover:scale-100
shadow-2xl border-2 w-full p-4 rounded-lg">
Bewerbung zurückziehen
</button>
</div>
</div>
</div>
</div>
#endif
#endforeach
#endforeach
Here is the code for the modal:
<div id="delete_application_modal" class="modal fixed ml-96 top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white hidden">
<div class="mt-3 text-center text-xl">
Bewerbung zurückziehen
<div class="text-center text-sm mt-4">
</div>
</div>
<div class="items-center px-4 py-3">
<label for="delete_application" class="sr-only">Bewerbung zurückziehen</label>
<form action="{{ route('delete', $bewerbung->Bewerbung_ID) }}" method="post">
#csrf
<button type="submit" id="ok_btn" class="mb-4 pb-3 w-full text-white px-4 py-3 rounded text-base font-medium
bg-gradient-to-r from-green-400 to-blue-500 float-right shadow transition
duration-500 ease-in-out transform hover:-translate-y-1 hover:scale-100
shadow-2xl border-2 w-full p-4 rounded-lg">
Bewerbung zurückziehen
</button>
</form>
</div>
<div class="items-center px-4 py-3">
<button id="back_btn_tel" class="mb-4 pb-3 w-full text-white px-4 py-3 rounded text-base font-medium
bg-gradient-to-r from-green-400 to-blue-500 float-right shadow transition
duration-500 ease-in-out transform hover:-translate-y-1 hover:scale-100
shadow-2xl border-2 w-full p-4 rounded-lg">
zurück
</button>
</div>
</div>
#if(session()->has('message'))
<div class="alert alert-success">
{{ session()->get('message') }}
</div>
#endif
<script>
var delete_appl_modal = document.getElementById("delete_application_modal");
var open_modal = document.getElementById("delete_appl_btn");
var back_btn = document.getElementById("back_btn_tel");
open_modal.onclick = function () {
delete_appl_modal.style.display = "block";
}
back_btn.onclick = function () {
delete_appl_modal.style.display = "none";
}
window.onclick = function (event) {
if (event.target == modal) {
delete_appl_modal.style.display = "none";
}
}
</script>
Honestly, I have zero clue why it works for the first but not for the others, they have the same buttons, with the same name, id & everything.
Maybe one of you had a similar issue. I wish you all happy holidays!
Edit:
New code to open the modal:
<script>
var delete_appl_modal = document.querySelector('#cancel_appl_modal');
var open = document.querySelector('#open_btn');
var back_btn = document.querySelector('#back_btn_tel');
open.onclick = function () {
delete_appl_modal.style.display = "block";
}
back_btn.onclick = function () {
delete_appl_modal.style.display = "none";
}
window.onclick = function (event) {
if (event.target == modal) {
delete_appl_modal.style.display = "none";
}
}
</script>
When I use querySelectorALl then the first one doesn't work anymore as well
The id property is expected to be unique within a page, so when using getElementById once an element with that id has been located it doesn't continue searching for others.
As you have multiple button elements that you want to target, you will need to us something like querySelectorAll or getElementsByClassName to target every element that should trigger the modal to open.
An example to get you on the right direction.
<button class="open-modal">Button A</button>
<button class="open-modal">Button B</button>
<button class="open-modal">Button C</button>
let buttons = document.querySelectorAll('.open-modal');
buttons.forEach(button => {
button.addEventListener('click', function (event) {
// this is where you would open the modal
// delete_appl_modal.style.display = 'block';
console.log(event.target.innerHTML);
})
});
Example JSFiddle
I just ran into an issue I just can't get my head around.
I have a site with all the applications a user has made, looking like this:
I have a button to delete/cancel on each post this exact post (Bewerbung zurückziehen).
When pressing that button, a modal opens with some text. When he presses the delete button in the modal the application is canceled if the user is sure to delete it.
However, it is always the first on the page that gets deleted, not the one on which the button was pressed.
I have to somehow get the application's ID on which the button was pressed, but I have zero clue on how to do it.
Here is the blade code:
<div class="flex-grow">
#foreach($bewerbungen as $bewerbung)
#foreach($stellenanzeigen_names as $stellenanzeigen_name)
#if($bewerbung->Stellenanzeigen_ID === $stellenanzeigen_name->Stellenanzeigen_ID)
<div class="p-10 grid-cols-3 grid-rows-3 gap-4 shadow-2xl mb-10 grey_bg border-solid border-2 border-black rounded-lg">
<!--Card 1-->
<div>
{{ $stellenanzeigen_name->Titel }}
<hr class="border-black">
</div>
<div class="pt-4 pl-8 font-medium text-xl font-bold font-serif">
ID der Bewerbung: {{ $bewerbung->Bewerbung_ID }}
</div>
<div class="pt-4 pl-8 pb-3 font-medium text-xl font-bold font-serif">
ID der Stellenanzeige: {{ $bewerbung->Stellenanzeigen_ID }}
</div>
<div class="flex justify-end">
<button type="submit"
name="open_btn"
class="open-btn mr-8 text-black px-4 py-3 rounded text-base font-medium button_bg float-right shadow transition duration-500 ease-in-out transform hover:-translate-y-1 hover:scale-100"
>
Bewerbung zurückziehen
</button>
</div>
<div id="cancel_appl_modal"
class="modal fixed ml-96 top-20 mx-auto p-5 border w-96 shadow-lg rounded-md post_bg hidden text-white">
<div class="mt-3 text-center text-2xl">
Bewerbung zurückziehen
</div>
<div class="items-center px-4 py-3">
<label for="neue_telefonnummer" class="sr-only">Neue Telefonnummer</label>
<form method="post"
action="{{ route('delete', $bewerbung->Bewerbung_ID) }}">
#csrf
<div class="text-lg mb-4">
Wenn Sie die Bewerbung zurückziehen haben Sie keinen Zugriff mehr
auf alle Daten.
Die Daten werden jedoch noch im System archiviert.
</div>
<button type="submit"
id="ok_btn"
class="mb-4 pb-3 w-full text-black px-4 py-3 rounded text-base font-medium bg-teal float-right shadow transition duration-500 ease-in-out transform hover:-translate-y-1 hover:scale-100 shadow-2xl border-2 w-full p-4 rounded-lg"
>
Bewerbung zurückziehen
</button>
</form>
</div>
<div class="items-center px-4 py-3">
<button id="back_btn"
class="mb-4 pb-3 w-full text-black px-4 py-3 rounded text-base font-medium bg-teal float-right shadow transition duration-500 ease-in-out transform hover:-translate-y-1 hover:scale-100 shadow-2xl border-2 w-full p-4 rounded-lg"
>
zurück
</button>
</div>
</div>
</div>
#endif
#endforeach
#endforeach
</div>
This is the JS code for the modal:
let buttons = document.querySelectorAll('.open-btn');
var delete_appl_modal = document.getElementById("cancel_appl_modal");
buttons.forEach((button) => {
button.addEventListener('click', function (event) {
// this is where you would open the modal
delete_appl_modal.style.display = 'block';
console.log(event.target.innerHTML);
})
});
var submit_btn = document.getElementById("ok_btn");
var back_btn = document.getElementById("back_btn");
open.onclick = function () {
delete_appl_modal.style.display = "block";
}
back_btn.onclick = function () {
delete_appl_modal.style.display = "none";
}
window.onclick = function (event) {
if (event.target == modal) {
delete_appl_modal.style.display = "none";
}
}
This is your form :
<form method="post" action="{{ route('delete', $bewerbung->Bewerbung_ID)}}">
but it's in a loop, so presumably you are creating lots of them, each with the same button with the same ID :
<button type="submit" id="ok_btn" ... >
Since ID has to be unique, when your javascript fires, it looks for the element with ID "ok_btn" to submit the relevant form. Since there are lots (again, ID should be unique) then it just submits the first one it comes to. So it will always just delete the first one on the page.
My suggestion would be :
Don't put the form or the modal in the loop.
Put the modal at the end, with the form inside it, and within the form have a hidden field (called, say, "delete_id".
Use javascript to populate the "delete_id" with the relevant ID of the thing to be deleted when the user clicks to bring up the modal.
Use the confirmation button to submit the form, as you do at the moment.
I found a solution with a small workaround!
I moved the modal out of the loops, as suggested in the comments / answers, and then I added two hidden input fields:
<form method="post"
action="{{ route('delete', $bewerbung->Bewerbung_ID) }}">
#csrf
<div class="text-lg mb-4">
Wenn Sie die Bewerbung zurückziehen haben Sie keinen Zugriff mehr
auf alle Daten.
Die Daten werden jedoch noch im System archiviert.
</div>
<input type="hidden" id="email" name="email" value="{{ $bewerbung->bewerber_email }}">
<input type="hidden" id="delete_id" name="delete_id" value="">
<button type="submit" id="ok_btn" class="mb-4 pb-3 w-full text-black px-4 py-3 rounded text-base font-medium
bg-teal float-right shadow transition
duration-500 ease-in-out transform hover:-translate-y-1 hover:scale-100
shadow-2xl border-2 w-full p-4 rounded-lg">
Bewerbung zurückziehen
</button>
</form>
So with the first field the email of the user is passed to the controller and with the second one I assign the value with this javascript code:
function reply_click(clicked_id)
{
document.getElementById("delete_id").value = clicked_id;
}
The button that open the modal now looks like this:
<button type="submit" name="open_btn" class="open-btn mr-8 text-black px-4 py-3 rounded text-base font-medium
button_bg float-right shadow transition
duration-500 ease-in-out transform hover:-translate-y-1 hover:scale-100" id="{{$bewerbung->Bewerbung_ID}}" onclick="reply_click(this.id)">Bewerbung
zurückziehen
</button>
Thanks to all in the comments, your hints led me to the right direction :)
In my Incomplete task and complete task : I want when I check my incomplete task to complete task I don't want to show my update button only Task name and a Delete button will be there, nothing else:
please see on my JS file: an completeTask() function to understand the problem more:
HTML:
<p class="text-2xl py-1 font-bold">
Incomplete Tasks
</p>
<hr>
<ul id="items">
<li class="py-5 px-2 item"><input type="checkbox" />
<label>Task Name</label>
<button class="update py-1 ml-12 px-2 text-md text-white rounded bg-gray-400 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-green-600 focus:ring-opacity-50">Update</button>
</li>
<li class="py-5 px-2 item"><input type="checkbox" />
<label>Task Name</label>
<button class="update py-1 ml-12 px-2 text-md text-white rounded bg-gray-400 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-green-600 focus:ring-opacity-50">Update</button>
</li>
<li class="py-5 px-2 item"><input type="checkbox" />
<label>Task Name</label>
<button class="update py-1 ml-12 px-2 text-md text-white rounded bg-gray-400 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-green-600 focus:ring-opacity-50">Update</button>
</li>
</ul>
</div>
</div>
<div class="bg-white p-6 rounded">
<div>
<p class="text-2xl py-1 font-bold">
Completed Tasks
</p>
<hr>
<ul id="items2">
<li class="py-5 px-2 item">
<label>Task Name</label>
<button class="delete py-1 ml-12 px-2 text-md text-white rounded bg-red-400 hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-600 focus:ring-opacity-50">Delete</button>
</li>
</ul>
</div>
JS file:
let completeTask = function(){
let listItem = this.parentNode;
let deleteBtn = document.createElement('button');
deleteBtn.innerText = 'Delete';
deleteBtn.className = 'delete';
deleteBtn.style.paddingLeft = '10px';
listItem.appendChild(deleteBtn);
let checkBox = listItem.querySelector('input[type="checkbox"]');
checkBox.remove();
completeUl.appendChild(listItem);
//here my checkbox I successfully remove it, but in the same way when I do for update button it don't work. //
bindDeleteItems(listItem,deleteTask);
}
Create a default class name like "unchecked/not completed". When you select a task, conditionally check is it checked or not. If it is selected then add a class "checked/completed" and hide the updated button by using a hidden tag before the class name.
So, first of all in the "completeTask" function, when you check the checkbox, conditionally add an extra class in the Update button "Completed".
Then again run the querySelector for finding the class "completed". After that remove that button form the ListItems.