Laravel Livewire, prevent selection lists from scrolling up on update - laravel

I am using Laravel Livewire. I'm intrigued by it's concept, but it's also quite confusing in certain specific situations. I am trying to make a selection list that comes up as a modal like so:
This is the "parent" template:
<x-slot name="breadcrumbs">
#include('breadcrumbs', [ 'path' => ['roles' => __('messages.roles')]])
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto">
<x-jet-action-message class="mr-3" on="created">
{{ __('messages.created_role') }}
</x-jet-action-message>
<div class="sm:flex sm:items-center">
<div class="sm:flex-auto">
<p class="mt-2 text-sm text-gray-700">{{ __('messages.all_roles_in_system') }}</p>
</div>
<div class="mt-4 sm:mt-0 sm:ml-16 sm:flex-none">
<a href="#" wire:click="$emitTo('roles.add-role-form', 'showForm')" class="button inline-flex items-center justify-center rounded-md border border-transparent bg-joij-green-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-joij-green-700 focus:outline-none focus:ring-2 focus:ring-joij-green-500 focus:ring-offset-2 sm:w-auto">
{{ __('messages.add_role') }}
</a>
</div>
</div>
<livewire:roles.add-role-form />
<livewire:roles.role-list />
</div>
</div>
The role-list looks like this:
<div class="mt-8 flex flex-col">
<div class="-my-2 -mx-4 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div class="inline-block min-w-full py-2 align-middle md:px-6 lg:px-8">
<div class="overflow-hidden shadow ring-1 ring-black ring-opacity-5 md:rounded-lg">
<table class="min-w-full divide-y divide-gray-300">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">
<a href="#" class="group inline-flex">
{{__('messages.name')}}
<span class="invisible ml-2 flex-none rounded text-gray-400 group-hover:visible group-focus:visible">
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/>
</svg>
</span>
</a>
</th>
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-6">
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 bg-white">
#foreach ($roles as $role)
<tr class="{{ $role->uuid === $activeRole ? 'bg-joij-green-200' : 'bg-white' }}" wire:key="key-{{ $role->uuid }}">
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium {{ $role->uuid === $activeRole ? 'text-white' : 'text-gray-900' }} sm:pl-6">{{ $role->name }}</td>
<td class="whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6">
<button wire:click="toggleActiveRole('{{ $role->uuid }}')" type="button" class="inline-flex items-center rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium leading-4 text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-joij-green-500 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-30">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-3 h-3">
<path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" />
</svg>
</button>
<button type="button" class="inline-flex items-center rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium leading-4 text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-joij-green-500 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-30">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-3 h-3">
<path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" />
</svg>
</button>
</td>
</tr>
#if ($role->uuid === $activeRole)
<tr wire:key="sub-{{ $role->uuid }}">
<td colspan="2" class="relative mb-0 pb-0">
<livewire:roles.permission-list wire:key="$role->uuid" :role="$role" />
</td>
</tr>
#endif
#endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
And then I have the permission-list:
<table class="min-w-full divide-y divide-gray-300 bg-gray-50">
<thead>
<tr class="bg-gray-100">
<th scope="col" class="py-3.5 pl-6 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">Permissions</th>
</tr>
</thead>
<tbody>
#foreach ($role->permissions()->get() as $permission)
<tr>
<td class="px-6 py-2 text-sm text-gray-500 lg:table-cell">{{ $permission->identifier }}</td>
</tr>
#endforeach
<tr>
<td class="px-6 py-3.5 text-sm text-gray-500 lg:table-cell">
<livewire:roles.permission-dropdown :role="$role" />
</td>
</tr>
</tbody>
</table>
And then the permission-dropdown:
<div>
<button
type="button" wire:click="togglePermissionList"
class="relative cursor-default rounded-md border border-gray-300 bg-white py-2 pl-3 pr-10 text-left shadow-sm {{ $showPermissionList ? 'bg-joij-green-500 text-white border-joij-green-500 outline-none ring-1 ring-joij-green-500 ': 'hover:bg-joij-green-100 hover:text-gray-800 ' }}sm:text-sm"
aria-haspopup="listbox" aria-expanded="true" aria-labelledby="listbox-label">
<span class="flex items-center">
<span class="block truncate">{{__('messages.add_permissions')}}</span>
</span>
<span class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6v12m6-6H6"/>
</svg>
</span>
</button>
#if ($showPermissionList)
<div class="fixed top-1/2 left-1/2 -translate-y-1/2 -translate-x-1/2 drop-shadow-md bg-white min-h-[400px] max-h-[650px] ring-1 ring-gray-300 rounded-md w-96 focus:outline-none sm:text-sm">
<ul wire:key="key-{{ time() }}"
class="absolute left-0 top-0 right-0 bottom-14 overflow-auto text-base border-b border-opacity-50"
tabindex="-1">
#foreach ($permissions as $detailedPermission)
<li wire:click="toggleSelectPermission('{{ $detailedPermission->uuid }}')"
wire:key="key-{{ $detailedPermission->uuid }}"
class="text-gray-900 relative cursor-default select-none py-2 pl-3 pr-9 hover:bg-gray-100 hover:cursor-pointer block"
role="option"
>
<div class="flex items-center">
<span class="inline-block h-2 w-2 flex-shrink-0 rounded-full {{ $detailedPermission->selected ? 'bg-joij-green-100' : 'bg-gray-200' }}"
aria-hidden="true"></span>
<span class="font-normal ml-3 block truncate">{{ $detailedPermission->identifier }}</span>
</div>
#if ($detailedPermission->selected)
<span class="text-joij-green-600 absolute inset-y-0 right-0 flex items-center pr-4">
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"
aria-hidden="true">
<path fill-rule="evenodd"
d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z"
clip-rule="evenodd"/>
</svg>
</span>
#endif
</li>
#endforeach
</ul>
<button
type="button"
wire:click="togglePermissionList"
class="absolute bottom-2 right-2 cursor-default rounded-md border border-gray-300 bg-white py-2 pl-3 pr-10 text-left shadow-sm bg-joij-green-500 text-white border-joij-green-500 outline-none ring-1 ring-joij-green-500 sm:text-sm"
aria-haspopup="listbox"
aria-expanded="true"
aria-labelledby="listbox-label"
>
<span class="flex items-center">
<span class="block truncate">Close</span>
</span>
<span class="absolute inset-y-0 right-0 flex items-center pr-2">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</span>
</button>
</div>
#endif
</div>
If I click the <li>. The wire:click="toggleSelectPermission('{{ $detailedPermission->uuid }}') . Is called to assign this permission to a role. This works! But the list will scroll up on every selection making this into an unusable solution. Is there something I can do to prevent the list from scrolling back up again?

Related

Make selected item current

EDIT: Full code for the 3 most likely files are found here.
https://codepen.io/arcticmedia-ryan/project/editor/ZEQwmN
I am not sure how best to explain this so please let me know if you want more. I am building a chat room app. When a person opens up the main vue, they are presented with a "Room List" - from there they can click enter and join the room. The issue is, when they click join, it opens up the tab for the room but doesnt make it active. I feel like I am just banging my head around a simple problem
There is a prop called "SelectedRoomID" that needs to be updated from "undefined" to the room that is selected from the list.
RoomList.vue
<!-- This example requires Tailwind CSS v2.0+ -->
<template>
<TransitionRoot as="template" :show="isOpen">
<Dialog as="div" class="fixed z-10 inset-0 overflow-y-auto" #close="$emit('onClose')">
<div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<TransitionChild as="template" enter="ease-out duration-300" enter-from="opacity-0"
enter-to="opacity-100" leave="ease-in duration-300" leave-from="opacity-100"
leave-to="opacity-0">
<DialogOverlay class="fixed inset-0 bg-gray-700 bg-opacity-75 transition-opacity"/>
</TransitionChild>
<!-- This element is to trick the browser into centering the modal contents. -->
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span>
<TransitionChild as="template" enter="ease-out duration-300"
enter-from="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enter-to="opacity-100 translate-y-0 sm:scale-100" leave="ease-in duration-300"
leave-from="opacity-100 translate-y-0 sm:scale-100"
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95">
<div class="inline-block align-bottom bg-black bg-opacity-20 rounded-lg px-6 pt-5 pb-4 text-left overflow-hidden shadow-2xl transform transition-all sm:my-8 sm:align-middle sm:p-6">
<div class="sm:flex sm:items-start">
<div class="flex flex-col">
<div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div class="align-middle inline-block min-w-full sm:px-4 lg:px-5">
<div class="shadow overflow-hidden border-8 border-gray-800 dark:border-gray-900 sm:rounded-lg">
<table class="min-w-full divide-y divide-gray-800">
<thead class="bg-gray-800 dark:bg-gray-900">
<tr>
<th scope="col"
class="px-6 py-3 text-left text-s font-medium text-gray-50 uppercase tracking-wider">
Room
</th>
<th scope="col"
class="px-6 py-3 text-left text-s font-medium text-gray-50 uppercase tracking-wider">
Description
</th>
<th scope="col"
class="px-6 py-3 text-left text-s font-medium text-gray-50 uppercase tracking-wider">
Type
</th>
<th scope="col"
class="px-6 py-3 text-left text-s font-medium text-gray-50 uppercase tracking-wider">
Users
</th>
<th scope="col" class="relative px-6 py-3">
<button type="button"
class="bg-white rounded-md text-gray-400 hover:text-gray-500 "
#click="$emit('onClose')">
<div class="hidden sm:block absolute top-0 right-0 pt-4 pr-4">
<span class="sr-only">Close</span>
<XIcon class="top-1 right-1 absolute h-6 w-6 text-gray-50 " aria-hidden="true"/>
</div>
</button>
<span class="sr-only">Enter</span>
</th>
</tr>
</thead>
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-300 dark:divide-gray-600">
<tr v-for="room in $store.state.rooms.rooms" :key="room.id">
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="flex-shrink-0 h-10 w-10">
<img class="h-10 w-10 rounded-full" :src="room.image"
alt=""/>
</div>
<div class="ml-4">
<div class="text-md font-medium text-gray-900 dark:text-gray-50">
{{ room.name }}
</div>
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-md text-gray-900 dark:text-gray-50">{{ room.description }}</div>
</td>
<td class="px-2 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-s leading-5 font-medium rounded-full">
<div v-if="room.is_private === true" class="rounded-full py-1 px-2 bg-red-100 text-red-800 dark:bg-red-800 dark:text-red-100">
<span>Private</span>
</div>
<div v-else-if="room.is_private === false" class="rounded-full py-1 px-2 bg-green-100 text-green-800 dark:bg-green-800 dark:text-green-100">
<span>Public</span>
</div>
<div v-else-if="room.is_private === 'true'" class="rounded-full py-1 px-2 bg-red-100 text-red-800 dark:bg-red-800 dark:text-red-100">
<span>Private</span>
</div>
<div v-else-if="room.is_private === 'false'" class="rounded-full py-1 px-2 bg-green-100 text-green-800 dark:bg-green-800 dark:text-green-100">
<span>Public</span>
</div>
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-center">
<a class="text-md font-medium text-gray-900 dark:text-gray-50">99</a>
</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-md font-medium">
<div class="flex rounded-full py-2 px-4 bg-indigo-700 hover:bg-indigo-900">
<a href="#" #click="joinRoom(room)"
class="text-white">Enter</a>
</div>
</td>
</tr>
</tbody>
</table>
<div class="bg-gray-800 dark:bg-gray-900">
<div class="flex justify-end px-4 py-3 text-left text-s font-medium text-gray-50 uppercase tracking-wider">
<span class=" px-2 pt-2 text-xs leading-5 font-semibold rounded-full">
<a href="#">
<div class="flex rounded-full py-1 px-2 bg-green-700 text-green-100 hover:bg-green-800">
<PlusIcon class="h-5 w-5"/><span class="text-sm font-bold pl-0.5">Create Room</span>
</div>
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</TransitionChild>
</div>
</Dialog>
</TransitionRoot>
</template>
<script>
import {Dialog, DialogOverlay, DialogTitle, TransitionChild, TransitionRoot} from '#headlessui/vue'
import {ExclamationIcon, XIcon, PlusIcon} from '#heroicons/vue/outline'
import {types as RoomTypes} from "../../../Store/modules/rooms/rooms.types";
export default {
components: {
Dialog,
DialogOverlay,
DialogTitle,
TransitionChild,
TransitionRoot,
ExclamationIcon,
XIcon,
PlusIcon,
},
props: ['rooms', 'selectedRoomId'],
emits: ['onSelectRoom', 'onLeaveRoom', 'onClose'],
methods: {
joinRoom(room) {
this.$store.dispatch(RoomTypes.JOIN_ROOM, room);
this.selectedRoomId = this.room;
this.$emit('onClose');
}
},
props: {
isOpen: Boolean,
usersCount: Boolean
},
}
</script>
Main.vue
SNIPPET OF CODE
<section aria-labelledby="primary-heading"
class="dark:bg-gray-900 min-w-0 flex-1 h-full flex flex-col overflow-hidden lg:order-last">
<room-tabs :selectedRoomId="currentRoom.id" :rooms="joinedRooms"
#onSelectRoom="currentRoom = $event" #onLeaveRoom="leaveRoom($event)"/>
<message-container :messages="messages"
class="h-full pb-2 mb-2 pt-0 mt-0 shadow-md overflow-y-auto"/>
<input-box
:room="currentRoom"
v-on:messagesent="getMessages"
class="dark:bg-gray-800 px-6 pb-6 pt-4 dark:border-t-2 dark:border-gray-600 bottom-0 sticky"
/>
</section>
I know its inside methods: joinRoom that needs to change and I know its wrong where this.selectedRoomId is - I just dont know what I need to change/fix to make it turn the selected room into the active room when you click join.
Any help would be very much appreciated!
I would use mapState to effectively watch the value in the store that is being updated by this.$store.dispatch(RoomTypes.JOIN_ROOM, room);
So in a component that needs to know this value:
computed: {
...mapState(['STORE_NAME', 'STORE_VALUE']),
},
and then you should be able to use this.STORE_VALUE as a dynamically updated value

I can't dispatch event in Alpinejs

I am using Laravel 8, Alpinejs and Livewire and having this problem:
This is my index file:
#extends('dashboard')
#section('content')
<header class="max-w-7xl mx-auto bg-white flex items-center justify-between">
<div class="mx-9 py-6 mt-4">
<h1 class="text-3xl font-bold text-gray-900">
Boards
</h1>
</div>
<div class="mx-9 py-6 mt-4">
<a href="#" #click="
$dispatch('custom-event')
"
class="w-28 text-base text-white bg-blue hover:text-gray-50 hover:bg-blue-hover rounded-xl py-2 px-3 leading-none transition ease-in duration-150 text-center">
Create new board
</a>
</div>
</header>
<livewire:boards-table
:boards="$boards"
/>
<livewire:create-board />
#endsection
When I click the "Create new board" button in the header tag, I want the create-board livewire component to be displayed. So I used #click="$dispatch('custom-event').
And here is my create-board file:
<div
x-cloak
x-data="{ isOpen: false }"
x-show="isOpen"
#keydown.escape.window="isOpen = false"
#custom-event.window="isOpen = true"
class="fixed z-20 inset-0 overflow-y-auto"
aria-labelledby="modal-title"
role="dialog"
aria-modal="true"
>
<div class="flex items-end justify-center min-h-screen">
<div x-show.transition.opacity="isOpen" class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"
aria-hidden="true">
</div>
<div x-show.transition.origin.bottom.duration.300ms="isOpen"
class="modal bg-white rounded-tl-xl rounded-tr-xl overflow-hidden transform transition-all sm:max-w-lg sm:w-full">
<div class="absolute top-0 right-0 pt-6 pr-6">
<button #click="isOpen = false" class="text-gray-400 hover:text-gray-500">
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clip-rule="evenodd" />
</svg>
</button>
</div>
<div class="bg-white sm:p-6 my-3">
<h3 class="text-center text-xl font-bold text-gray-900">Create a new board</h3>
<form wire:submit.prevent="createBoard" action="#" method="POST" class="space-y-4 px-4 pt-6">
<div>
<input wire:model.defer="boardName" type="text"
class="w-full bg-gray-100 rounded-xl placeholder-gray-900 border-none font-semibold px-4 text-sm"
placeholder="Board name">
</div>
<div>
<input wire:model.defer="urlName" type="text"
class="w-full bg-gray-100 rounded-xl placeholder-gray-900 border-none font-semibold px-4 py-2 text-sm"
placeholder="Short name (used in board URL)">
</div>
<div class="flex items-center justify-end">
<button type="submit"
class="text-center w-44 bg-blue font-bold h-11 text-sm text-white rounded-xl border border-blue hover:bg-blue-hover transition duration-150 ease-in px-6 py-3 mr-4 mt-2">Create new board</button>
</div>
</form>
</div>
</div>
</div>
</div>
But when I click on "Create new board" button, nothing happens.
Create-board component is still rendered in the browser.

Laravel Navigation Menu Setup Issue

I am doing a blog project using Laravel, Livewire, Blade. I have a problem creating the navigation bar having "Dashboard", "Post", "Page", "Contact Us" in the same line as in picture 2.
The navigation I am having right now looks like in picture 1 which only "Dashboard", "Posts", "Pages" in the same line, and "Contact Us" are in a different line. Even the "Dashboard" is in the same line but the space between is larger than the space between "Posts", "Pages". Can someone help me to fix it?
Picture 1
Picture 2
navigation-menu.blade.php
<nav x-data="{ open: false }" class="bg-white border-b border-gray-100">
<!-- Primary Navigation Menu -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex">
<!-- Logo -->
<div class="flex-shrink-0 flex items-center">
<a href="{{ route('posts') }}">
<x-jet-application-mark class="block h-9 w-auto" />
</a>
</div>
<!-- Navigation Links -->
<x-jet-nav-link href="{{ route('dashboard') }}" :active="request()->routeIs('dashboard')">
{{ __('Dashboard') }}
</x-jet-nav-link>
<div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
<x-jet-nav-link href="{{ route('posts') }}" :active="request()->routeIs('posts')">
{{ __('Posts') }}
</x-jet-nav-link>
</div>
<!--Pages Dropdown -->
<div class="ml-3 mt-4 relative">
<x-jet-dropdown align="right" width="48">
<x-slot name="trigger">
<span class="inline-flex rounded-md">
<button type="button" class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150">
{{ __('Pages') }}
<svg class="ml-2 -mr-0.5 h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
</span>
</x-slot>
<x-slot name="content">
#foreach(\App\Models\Page::where('user_id', Auth::user()->id)->get() as $page)
<x-jet-dropdown-link href="pages/{{__($page['title'])}}">
{{ __($page['title']) }}
</x-jet-dropdown-link>
#endforeach
</x-slot>
</x-jet-dropdown>
<x-jet-nav-link href="{{ route('contact-form') }}" :active="request()->routeIs('contact-form')">
{{ __('Contact Us') }}
</x-jet-nav-link>
</div>
</div>
<div class="hidden sm:flex sm:items-center sm:ml-6">
<!-- Teams Dropdown -->
#if (Laravel\Jetstream\Jetstream::hasTeamFeatures())
<div class="ml-3 relative">
<x-jet-dropdown align="right" width="60">
<x-slot name="trigger">
<span class="inline-flex rounded-md">
<button type="button" class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:bg-gray-50 hover:text-gray-700 focus:outline-none focus:bg-gray-50 active:bg-gray-50 transition ease-in-out duration-150">
{{ Auth::user()->currentTeam->name }}
<svg class="ml-2 -mr-0.5 h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
</span>
</x-slot>
<x-slot name="content">
<div class="w-60">
<!-- Team Management -->
<div class="block px-4 py-2 text-xs text-gray-400">
{{ __('Manage Team') }}
</div>
<!-- Team Settings -->
<x-jet-dropdown-link href="{{ route('teams.show', Auth::user()->currentTeam->id) }}">
{{ __('Team Settings') }}
</x-jet-dropdown-link>
#can('create', Laravel\Jetstream\Jetstream::newTeamModel())
<x-jet-dropdown-link href="{{ route('teams.create') }}">
{{ __('Create New Team') }}
</x-jet-dropdown-link>
#endcan
<div class="border-t border-gray-100"></div>
<!-- Team Switcher -->
<div class="block px-4 py-2 text-xs text-gray-400">
{{ __('Switch Teams') }}
</div>
#foreach (Auth::user()->allTeams() as $team)
<x-jet-switchable-team :team="$team" />
#endforeach
</div>
</x-slot>
</x-jet-dropdown>
</div>
#endif
<!-- Settings Dropdown -->
<div class="ml-3 relative">
<x-jet-dropdown align="right" width="48">
<x-slot name="trigger">
#if (Laravel\Jetstream\Jetstream::managesProfilePhotos())
<button class="flex text-sm border-2 border-transparent rounded-full focus:outline-none focus:border-gray-300 transition duration-150 ease-in-out">
<img class="h-8 w-8 rounded-full object-cover" src="{{ Auth::user()->profile_photo_url }}" alt="{{ Auth::user()->name }}" />
</button>
#else
<span class="inline-flex rounded-md">
<button type="button" class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150">
{{ Auth::user()->name }}
<svg class="ml-2 -mr-0.5 h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
</span>
#endif
</x-slot>
<x-slot name="content">
<!-- Account Management -->
<div class="block px-4 py-2 text-xs text-gray-400">
{{ __('Manage Account') }}
</div>
<x-jet-dropdown-link href="{{ route('profile.show') }}">
{{ __('Profile') }}
</x-jet-dropdown-link>
#if (Laravel\Jetstream\Jetstream::hasApiFeatures())
<x-jet-dropdown-link href="{{ route('api-tokens.index') }}">
{{ __('API Tokens') }}
</x-jet-dropdown-link>
#endif
<div class="border-t border-gray-100"></div>
<!-- Authentication -->
<form method="POST" action="{{ route('logout') }}">
#csrf
<x-jet-dropdown-link href="{{ route('logout') }}"
onclick="event.preventDefault();
this.closest('form').submit();">
{{ __('Log Out') }}
</x-jet-dropdown-link>
</form>
</x-slot>
</x-jet-dropdown>
</div>
</div>
<!-- Hamburger -->
<div class="-mr-2 flex items-center sm:hidden">
<button #click="open = ! open" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out">
<svg class="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
<path :class="{'hidden': open, 'inline-flex': ! open }" class="inline-flex" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
<path :class="{'hidden': ! open, 'inline-flex': open }" class="hidden" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
</div>
<!-- Responsive Navigation Menu -->
<div :class="{'block': open, 'hidden': ! open}" class="hidden sm:hidden">
<div class="pt-2 pb-3 space-y-1">
<x-jet-responsive-nav-link href="{{ route('posts') }}" :active="request()->routeIs('posts')">
{{ __('Posts') }}
</x-jet-responsive-nav-link>
</div>
<!-- Responsive Settings Options -->
<div class="pt-4 pb-1 border-t border-gray-200">
<div class="flex items-center px-4">
#if (Laravel\Jetstream\Jetstream::managesProfilePhotos())
<div class="flex-shrink-0 mr-3">
<img class="h-10 w-10 rounded-full object-cover" src="{{ Auth::user()->profile_photo_url }}" alt="{{ Auth::user()->name }}" />
</div>
#endif
<div>
<div class="font-medium text-base text-gray-800">{{ Auth::user()->name }}</div>
<div class="font-medium text-sm text-gray-500">{{ Auth::user()->email }}</div>
</div>
</div>
<div class="mt-3 space-y-1">
<!-- Account Management -->
<x-jet-responsive-nav-link href="{{ route('profile.show') }}" :active="request()->routeIs('profile.show')">
{{ __('Profile') }}
</x-jet-responsive-nav-link>
#if (Laravel\Jetstream\Jetstream::hasApiFeatures())
<x-jet-responsive-nav-link href="{{ route('api-tokens.index') }}" :active="request()->routeIs('api-tokens.index')">
{{ __('API Tokens') }}
</x-jet-responsive-nav-link>
#endif
<!-- Authentication -->
<form method="POST" action="{{ route('logout') }}">
#csrf
<x-jet-responsive-nav-link href="{{ route('logout') }}"
onclick="event.preventDefault();
this.closest('form').submit();">
{{ __('Log Out') }}
</x-jet-responsive-nav-link>
</form>
<!-- Team Management -->
#if (Laravel\Jetstream\Jetstream::hasTeamFeatures())
<div class="border-t border-gray-200"></div>
<div class="block px-4 py-2 text-xs text-gray-400">
{{ __('Manage Team') }}
</div>
<!-- Team Settings -->
<x-jet-responsive-nav-link href="{{ route('teams.show', Auth::user()->currentTeam->id) }}" :active="request()->routeIs('teams.show')">
{{ __('Team Settings') }}
</x-jet-responsive-nav-link>
#can('create', Laravel\Jetstream\Jetstream::newTeamModel())
<x-jet-responsive-nav-link href="{{ route('teams.create') }}" :active="request()->routeIs('teams.create')">
{{ __('Create New Team') }}
</x-jet-responsive-nav-link>
#endcan
<div class="border-t border-gray-200"></div>
<!-- Team Switcher -->
<div class="block px-4 py-2 text-xs text-gray-400">
{{ __('Switch Teams') }}
</div>
#foreach (Auth::user()->allTeams() as $team)
<x-jet-switchable-team :team="$team" component="jet-responsive-nav-link" />
#endforeach
#endif
</div>
</div>
</div>
You are using the wrong div tag.
<!--Pages Dropdown -->
<div class="ml-3 mt-4 relative">
// remove the contact us code from here
</div>
<x-jet-nav-link href="{{ route('contact-form') }}" :active="request()->routeIs('contact-form')">
{{ __('Contact Us') }}
</x-jet-nav-link>

Using a modal to delete a user

I'm trying to create a modal that when you click delete it will delete a record, but first I need to be able to have
that modal pop up.
I know that the reason is because of this line $('#delete_{{ $user->id }}').click(function(){ but I'm not sure how to add the user id without having to add the <script>...</script> to the foreach loop
Or do I need to do that?
Here is my code
<table class="min-w-full divide-y divide-gray-200">
<thead>
<tr>
<th class="px-6 py-3 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
Name
</th>
<th class="px-6 py-3 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider text-right">
Add User
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
#foreach($users as $user)
<tr>
<td class="px-6 py-4 whitespace-no-wrap">
<div class="flex items-center">
<div class="ml-4">
<div class="text-sm leading-5 font-medium text-gray-900">
{{ $user->name }}
</div>
<div class="text-sm leading-5 text-gray-500">
{{ $user->email }}
</div>
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-no-wrap text-right text-sm leading-5 font-medium">
<button id="delete_{{ $user->id }}" class="bg-red-400 hover:bg-red-300 text-red-800 font-bold py-2 px-4 rounded inline-flex items-center">
Delete
</button>
</td>
</tr>
#endforeach
</tbody>
</table>
<div class="modal-display-none">
<div class="fixed z-10 inset-0 overflow-y-auto">
<div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity">
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
</div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen"></span>​
<div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline">
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="sm:flex sm:items-start">
<div class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10">
<svg class="h-6 w-6 text-red-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
</svg>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900" id="modal-headline">
Delete User
</h3>
<div class="mt-2">
<p class="text-sm leading-5 text-gray-500">
Are you sure you want to delete this user? <br>
This action cannot be undone.
</p>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<span class="flex w-full rounded-md shadow-sm sm:ml-3 sm:w-auto">
<form action="{{ route('users.delete', ['user' => $user->id]) }}" method="POST">
#method('DELETE')
#csrf
<button type="button"
class="inline-flex justify-center w-full rounded-md border border-transparent px-4 py-2 bg-red-600 text-base leading-6 font-medium text-white shadow-sm hover:bg-red-500 focus:outline-none focus:border-red-700 focus:shadow-outline-red transition ease-in-out duration-150 sm:text-sm sm:leading-5"
id="confirm_delete"
>
Delete
</button>
</form>
</span>
<span class="mt-3 flex w-full rounded-md shadow-sm sm:mt-0 sm:w-auto">
<button type="button" id="close" class="inline-flex justify-center w-full rounded-md border border-gray-300 px-4 py-2 bg-white text-base leading-6 font-medium text-gray-700 shadow-sm hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue transition ease-in-out duration-150 sm:text-sm sm:leading-5">
Cancel
</button>
</span>
</div>
</div>
</div>
</div>
</div>
<style>
.modal-display-none{
display: none;
}
.modal-display{
display: block;
}
</style>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script>
$(document).ready(function(){
$('#delete_{{ $user->id }}').click(function(){
console.log('delete button');
$('.modal-display-none').removeClass('modal-display-none').addClass('modal-display');
});
$('#confirm_delete').click(function(){
$('.modal-display').removeClass('modal-display').addClass('modal-display-none');
});
$('#close').click(function(){
$('.modal-display').removeClass('modal-display').addClass('modal-display-none');
});
});
</script>
replace your syntax (inside foreach)
<button id="delete_{{ $user->id }}" class="bg-red-400 hover:bg-red-300 text-red-800 font-bold py-2 px-4 rounded inline-flex items-center">Delete</button>
replace with this syntax bellow, it will show an alert to confirm the Delete action
{!! Form::open(['route' => ['users.delete', $user->id], 'method' => 'delete']) !!}
{!! Form::button('<i class="fa fa-trash"></i>', [
'type' => 'submit',
'class' => 'bg-red-400 hover:bg-red-300 text-red-800 font-bold py-2 px-4 rounded inline-flex items-center',
'onclick' => "return confirm('Are you sure want to delete this item?')"
]) !!}
{!! Form::close() !!}

Q: how to make use of Alpinejs and tailwindcss within Laravel?

I am trying to make use of Alpinejs using Adam Wathan's responsive navbar using vuejs, but i am experimenting if i can get it to work with Alpinejs.
app.blade.php
<head>
[...]
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine#v2.x.x/dist/alpine.min.js" defer></script>
[...]
</head>
In case you are wondering if Alpine is already loaded, it is working trying a simple dropdown toggle, but with this approach i find it hard to get it working.
Navbar.blade.php
#guest('applicant')
#else
<header class="bg-gray-900 sm:flex sm:items-center sm:justify-between xl:bg-white" x-data="dropdown()">
<div class="flex justify-between px-4 py-3 xl:w-72 xl:bg-gray-900 xl:justify-center xl:py-5">
<div>
[...]
</div>
<div class="flex sm:hidden">
<button x-on:click="open" type="button"
class="px-2 text-gray-500 hover:text-white focus:outline-none focus:text-white">
<svg class="h-6 w-6 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path x-if="isOpen" fill-rule="evenodd" clip-rule="evenodd"
d="M18.278 16.864a1 1 0 0 1-1.414 1.414l-4.829-4.828-4.828 4.828a1 1 0 0 1-1.414-1.414l4.828-4.829-4.828-4.828a1 1 0 0 1 1.414-1.414l4.829 4.828 4.828-4.828a1 1 0 1 1 1.414 1.414l-4.828 4.829 4.828 4.828z" />
<path x-if="!isOpen" fill-rule="evenodd"
d="M4 5h16a1 1 0 0 1 0 2H4a1 1 0 1 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2z" />
</svg>
</button>
</div>
</div>
<nav class="sm:flex sm:items-center sm:px-4 xl:flex-1 xl:justify-between"
:class="{ 'hidden': !isOpen, 'block': isOpen }" x-show="open" x-on:click.away="close">
<div class="hidden xl:block xl:relative xl:max-w-xs xl:w-full">
[...]
</div>
<div class="sm:flex sm:items-center">
[...]
<div class="relative px-5 py-5 sm:py-0 sm:ml-4 sm:px-0">
[...]
<Dropdown class="hidden sm:block">
<template #trigger="{ hasFocus, isOpen }">
<span class="block h-8 w-8 overflow-hidden rounded-full border-2 "
:class="[(hasFocus || isOpen) ? 'border-white xl:border-indigo-500' : 'border-gray-600 xl:border-gray-300']">
<img class="h-full w-full object-cover"
src="https://images.unsplash.com/photo-1487412720507-e7ab37603c6f?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=256&q=80"
alt="">
</span>
</template>
<template #dropdown>
<div class="mt-3 bg-white xl:border rounded-lg w-48 py-2 shadow-xl">
<a href="#account" class="block hover:text-white text-gray-800 px-4 py-2 hover:bg-indigo-500">Account
settings</a>
<a href="#support"
class="block hover:text-white text-gray-800 mt-0 px-4 py-2 hover:bg-indigo-500">Support</a>
<a href="#sign-out" class="block hover:text-white text-gray-800 mt-0 px-4 py-2 hover:bg-indigo-500">Sign
out</a>
</div>
</template>
</Dropdown>
</div>
</div>
</nav>
</header>
<script>
function dropdown() {
return {
open: false,
open() {
this.show = true
},
close() {
this.show = false
},
toggle() {
this.isOpen = !this.isOpen
},
}
}
</script>
#endguest
You do not need to add the scripts to make a dropdown open and close.
You need to have x-data defined in a parent (to both button and dropdown) div. Then reference it in the button and/or dropdown elements.
A simple example:
<div x-data="{isOpen : false}">
<button x-on:click="isOpen = !isOpen" class="button">Menu</button>
<!-- you need to toggle isOpen state on click. You can also use #click just like in vue -->
<div x-show="isOpen" class="dropdown"> <!-- x-show to show and hide -->
Account settings
Support
</div>
</div>
That is all there is to make a dropdown using alpine js.
In my case i didn't my javascript nor installed it, i just used the cdn
{{-- scrip --}}
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine#v2.x.x/dist/alpine.min.js" defer></script>
and had installed tailwind css. my code is..
<div x-data="{dropdownMenu: false}" class="lg:inline-block relative">
<!-- Dropdown toggle button -->
<button #click="dropdownMenu = ! dropdownMenu"
class="text-base no-underline hover:bg-indigo-300 hover:text-cool-gray-900 rounded-3xl py-1 px-2 ">
<span class="sr-only">{{ Auth::user()->name }}</span>
<img class="h-8 w-8 rounded-full"
src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=4&w=256&h=256&q=60"
alt="avatar">
</button>
<!-- Dropdown list -->
<div x-show="dropdownMenu"
class="absolute right-0 py-2 mt-2 bg-white bg-gray-100 rounded-md shadow-xl w-44">
<a href="#"
class="block px-4 py-2 text-sm text-gray-300 text-gray-700 hover:bg-gray-400 hover:text-white">
Your Profile
</a>
<a href="#"
class="block px-4 py-2 text-sm text-gray-300 text-gray-700 hover:bg-gray-400 hover:text-white">
Settings
</a>
<a href="#"
class="block px-4 py-2 text-sm text-gray-300 text-gray-700 hover:bg-gray-400 hover:text-white">
Reports
</a>
<a href="{{ route('logout') }}"
class="block px-4 py-2 text-sm text-gray-300 text-gray-700 hover:bg-gray-400 hover:text-white"
onclick="event.preventDefault();document.getElementById('logout-form').submit();">{{ __('Logout') }}</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST"
class="hidden">
{{ csrf_field() }}
</form>
</div>
</div>
this was my result when i click the avatar..
i hope this will assist you solve your problem

Resources