Modal doesn't open on all buttons - javascript

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

Related

How can I align my text and put the button on the extrem right of my gray bar?

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>

Getting the correct ID to delete in site with multiple posts

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 :)

Play pause button not working on tab to tab

I am trying to build a function with jquery but I can't. I am trying to control video and audio with one button set for the different tabs. the problem is that the play pause button only controls the audio file not the video file in the second tab.
when we go to the second tab and press the button below it plays the same audio file.
see the sample code here
$(document).ready(function () {
$("#audio_play").on("click", function () {
$("#audio").get(0).play();
})
$("#audio_pause").on("click", function () {
$("#audio").get(0).pause();
})
$('.menu ul li:nth(1)').on("click", function () {
$("#audio_play").attr('id', 'video_play');
$("#audio_pause").attr('id', 'video_pause');
})
$("#video_play").on("click", function () {
$("#video").get(0).play();
})
$("#video_pause").on("click", function () {
$("#video").get(0).pause();
})
})
.con{
text-align:center;
width:156px;
margin:0 auto;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.1.2/tailwind.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/alpinejs/2.8.2/alpine.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="flex justify-center items-center w-full h-screen inset-x-0 mx-auto">
<!--actual component start-->
<div class="menu" x-data="setup()">
<ul class="flex justify-center items-center my-4">
<template x-for="(tab, index) in tabs" :key="index">
<li class="cursor-pointer py-2 px-4 text-gray-500 border-b-8"
:class="activeTab===index ? 'text-green-500 border-green-500' : ''" #click="activeTab = index"
x-text="tab"></li>
</template>
</ul>
<div class="w-full bg-white p-16 text-center mx-auto border">
<div x-show="activeTab===0">
<h1>Audio Player</h1>
<audio id="audio"
src="https://res.cloudinary.com/foxyplays989/video/upload/v1558369838/LetsGo.mp3"></audio>
</div>
<div x-show="activeTab===1">
<iframe id="video" class="w-full h-56"
src="https://player.vimeo.com/video/76979871?loop=false&byline=false&portrait=false&title=false&speed=true&transparent=0&gesture=media"
allowfullscreen allowtransparency allow="autoplay"></iframe>
</div>
<div x-show="activeTab===2">Content 3</div>
<div x-show="activeTab===3">Content 4</div>
</div>
</div>
<!--actual component end-->
</div>
<div class="flex con">
<button class="inline-block px-6 py-2 text-xs font-medium leading-6 text-center text-white uppercase transition bg-blue-700 rounded shadow ripple hover:shadow-lg hover:bg-blue-800 focus:outline-none" id="audio_play">play</button>
<button class="inline-block px-6 py-2 text-xs font-medium leading-6 text-center text-white uppercase transition bg-red-500 rounded shadow ripple hover:shadow-lg hover:bg-red-600 focus:outline-none" id="audio_pause">Pause</button>
</div>
<script>
function setup() {
return {
activeTab: 0,
tabs: [
"Tab No.1",
"Tab No.2",
]
};
};
</script>

AlpineJs, adding dynamic id to element and comparing on mouseover event

I want to display some data beloning to an image when a user hovers over it, how would I go adding and comparing id's from a livewire component ?
Livewire view
<div x-data="{tooltip : false}" class="grid grid-cols-3 gap-4 ml-2 antialiased text-gray-900">
<div #mouseover.away="{tooltip = false}">
#forelse($animals as $animal)
<img id="{{$animal->animals->id}}" x-on:mouseover="{tooltip = !tooltip}"
src="https://source.unsplash.com/random/350x350"
alt="Animal image"
class="object-cover rounded-lg shadow-md ">
<div x-show.transition="tooltip" class="absolute -mt-16 ">
<div class="p-6 bg-white rounded-lg shadow-lg">
<h4 class="mt-1 text-xl font-semibold leading-tight uppercase truncate">This is
: {{$animal->animals->name}}</h4>
<div class="mt-4">
<span class="font-semibold text-teal-600 text-md">4/5 ratings </span>
<span class="text-sm text-gray-600">(based on 234 ratings)</span>
</div>
</div>
</div>
#empty
<p class="text-center">No animals found</p>
#endforelse
</div>
</div>
Livewire class
class Dashboard extends Component
{
public function render()
{
$animal = UserAnimal::with('animals')->where('user_id', '=', Auth::id())->get();
return view('livewire.dashboard')->with('animals', $animal);
}
}
This snippet works when only one image is displayed, but as soon as another image is added the tooltip stops working,
E.g the user hovers over the first image and the name of that animal is displayed in the hovering tooltip.
Instead of having a global tooltip attribute on the parent div, I would use a tooltip attribute for each animal - which means you probably need to adjust your loop and html structure.
<div class="grid grid-cols-3 gap-4 ml-2 antialiased text-gray-900">
<div x-data="{tooltip : false}">
<img id="{{$animal->animals->id}}" x-on:mouseover="{tooltip = !tooltip}" x-on:mouseout="{tooltip = !tooltip}" src="https://source.unsplash.com/random/350x350" alt="Animal image" class="object-cover rounded-lg shadow-md ">
<div x-show.transition="tooltip" class="absolute -mt-16 ">
<div class="p-6 bg-white rounded-lg shadow-lg">
<h4 class="mt-1 text-xl font-semibold leading-tight uppercase truncate">This is
: A dog</h4>
<div class="mt-4">
<span class="font-semibold text-teal-600 text-md">4/5 ratings </span>
<span class="text-sm text-gray-600">(based on 234 ratings)</span>
</div>
</div>
</div>
</div>
<div x-data="{tooltip : false}">
<img id="{{$animal->animals->id}}" x-on:mouseover="{tooltip = !tooltip}" x-on:mouseout="{tooltip = !tooltip}" src="https://source.unsplash.com/random/350x350" alt="Animal image" class="object-cover rounded-lg shadow-md ">
<div x-show.transition="tooltip" class="absolute -mt-16 ">
<div class="p-6 bg-white rounded-lg shadow-lg">
<h4 class="mt-1 text-xl font-semibold leading-tight uppercase truncate">This is
: A cat</h4>
<div class="mt-4">
<span class="font-semibold text-teal-600 text-md">1/5 ratings </span>
<span class="text-sm text-gray-600">(based on 2 ratings)</span>
</div>
</div>
</div>
</div>
</div>
Example in Codepen

Why my function in html code is not being called?

I'm working on a Laravel Livewire project which uses TailwindCSS and AlpineJS. But my issue is about my setCountry() function not being called. I can see the parameters are being correctly passed but the function itself is not being called. The toggleCountriesHandler() function is working nicely.
I bet it is something under my nose, but I still can't figure it out, and I'm a begginer in programming.
Here's my code snippet:
toggleCountriesHandler = () => {
let toggleCountries = document.getElementById("countriesOpen");
if (toggleCountries.style.display === "none") {
toggleCountries.style.display = "block";
} else {
toggleCountries.style.display = "none";
}
}
setCountry = (country_id, country_code, country_name) => {
document.getElementById("country-id").value = country_id;
document.getElementById("selected-country").innerHTML = "<img class='w-5 h-5 rounded-full' src='img/flags/16/" + country_code + ".png'>" + "<span class='block ml-3 font-normal truncate'>" + country_name + "</span>";
document.getElementById("countriesOpen").style.display = "none";
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/1.2.0/tailwind.min.css" rel="stylesheet" />
<span class="block text-sm font-medium text-gray-700 transform translate-y-5">{{__("Country")}</span>
<div style="height: 42px;" class="relative flex items-center justify-center w-full pl-3.5 pr-10 text-left bg-white border border-gray-300 rounded-md shadow-sm cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<button onclick="toggleCountriesHandler()" class="block w-full truncate focus:outline-none">
<label id="selected-country" class="flex flex-row items-center text-gray-500">{{__("Select your country")}}</label>
</button>
<div class="absolute top-0 right-0 w-full mt-12 bg-white rounded-md shadow-lg sm:bg-white">
<input id="country-id" type="hidden" name="country_id">
<ul id="countriesOpen" style="display: none;" class="py-1 overflow-auto text-base rounded-md sm:border max-h-60 ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
#foreach(DB::table('countries')->get() as $country)
<li role="option" class="relative ">
<button onclick="setCountry({{ $country->id }}, '{{ $country->code }}', '{{ $country->name }}')" type="button" class="flex items-center w-full py-2 pl-3 space-x-3 cursor-default select-none text-extrading-text-primary sm:text-gray-900 pr-9 focus:outline-none hover:bg-indigo-600 hover:text-white">
<img class="w-5 h-5 rounded-full" src="{{ asset('img/flags/16/' . $country->code . '.png') }}">
<span class="block font-normal truncate">
{{$country->name}}
</span>
</button>
</li>
#endforeach
</ul>
</div>
</div>
I am posting my comment as an answer to close this question.
const toggletoggleCountriesHandler=()=>{}
const is usually used for the function declarations , since people don't change it.
Still you can use var , let also for declaration

Categories