I'm working on a Review module in laravel that can sort from All Ratings, Like, and Dislike. However, I'd also like to display the count of All Reviews, likes, and dislikes. Below is my code for the dropdown as well as the model.
Review Dropdown
#props(['routeName', 'username'])
<div class="flex items-center">
<span class="text-sm text-gray-700 uppercase m-1">{{ __('Review:') }}</span>
<div class="relative" x-data="{ open: false }" #click.outside="open = false" #close.stop="open = false">
<div #click="open = ! open">
<button class="flex items-center text-sm font-medium text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out">
<div>{{ App\Models\Review::RATING[request()->rating] ?? __('All') }}</div>
<div class="ml-1">
<svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><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>
</div>
</button>
</div>
<div x-show="open" class="absolute z-50 mt-2 w-20 rounded-md shadow-lg" style="display: none;" #click="open = false"> {{-- origin-top-right right-0 --}}
<div class="rounded-md ring-1 ring-black ring-opacity-5 py-1 bg-white overflow-y-auto py-1 h-30">
<x-dropdown-link href="{{ route($routeName, [$username]) }}?{{ http_build_query(request()->except('rating', 'page')) }}">
{{ __('All') }}
</x-dropdown-link>
#foreach(App\Models\Review::RATING as $value => $label)
<x-dropdown-link href="{{ route($routeName, [$username]) }}?rating={{ $value }}&{{ http_build_query(request()->except('rating', 'page')) }}">
{{ __($label) }}
</x-dropdown-link>
#endforeach
</div>
</div>
</div>
</div>
ReviewModel
class Review extends Model
{
use HasFactory;
protected $table = 'reviews';
protected $fillable = [
'customer_username',
'customer_id',
'business_id',
'rating',
'feedback'
];
const RATING = [
'1' => 'Dislike',
'2' => 'Like'
];
public function scopeFilter($query, $rating){
$query->when($rating ?? false, function ($query, $rating) {
$query->where(function ($query) use ($rating) {
$query->where('rating', $rating);
});
});
}
}
This is what I intend it to look like:
I did try adding ::count() and ->count() on App\Models\Review::RATING after the foreach in the dropdown but it broke the application.
Related
What am i not doing right? i'm woking on a livewire project that needs to get the grade_id's to show in show-component.blade.php, from Modules table which is related to a Grades table. My challenge is that, it only show a particular id, like the one in the mount section, so if i change it to 2 it will only show id's that are 2's, though thats really what i wanted but i can be change it manually.
use App\Models\Grade;
use App\Models\Module;
use Livewire\Component;
class ShowComponent extends Component
{
public $modules;
public $grades;
public function mount()
{
$this->modules = Module::all()->where("grade_id", "1");
}
public function render()
{
return view('livewire.show-component');
}
}
=========================================================================
show-component.blade.php
#foreach($modules as $module)
<div class="flex flex-col grid-cols-12 md:grid text-gray-50">
<div class="flex md:contents">
<div class="relative col-start-2 col-end-4 mr-10 md:mx-auto">
<div class="flex items-center justify-center w-6 h-full">
<div class="w-1 h-full bg-green-500 pointer-events-none"></div>
</div>
<div class="absolute w-6 h-6 -mt-3 text-center bg-green-500 rounded-full shadow top-1/2">
<i class="text-white fas fa-check-circle"></i>
</div>
</div>
<div class="w-full col-start-4 col-end-12 p-4 my-4 mr-auto bg-green-500 shadow-md rounded-xl">
<h2 class="mb-1 text-lg font-semibold">
{{ $module->name }}
</h2>
<p class="w-full leading-tight text-justify">
<a href="{{ url('storage/videos'.$module->video) }}">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd" />
</svg>
</a>
</p>
</div>
</div>
</div>
#endforeach
==================================================================
Module's Model
public function grade()
{
return $this->belongsTo(Grade::class, 'grade_id', 'id');
}
===============================================================
Grade's Model
public function curricula()
{
return $this->belongsTo(Curriculum::class, 'curricula_id', 'id');
}
public function module()
{
return $this->hasMany(Module::class);
}
If you want all Module records stored in your database table, you want to remove the where condition which is limiting the return value.
$this->modules = Module::all();
If you want just the grade_ids from your modules table, use pluck:
$grade_ids = Module::pluck('grade_id');
I think what you want is ..
Add
public $grade_id;
Then in mount
$this->modules = Module::where("grade_id", $this->grade_id)->get();
When you load your component you can pass grade_id to it
Why image preview is duplicated when using alpinejs and livewire in laravel 9?
Alpinejs already included in Laravel with defer.
The code drag and drop the images and shows their preview before submit. However, when I add wire:model=photo it duplicated the image preview, otherwise working perfectly.
Please have a look at below code which is inside livewire component.
<div x-data="dataFileDnD()" class="relative flex flex-col p-4 text-gray-400 border border-gray-200 rounded">
<form wire:submit.prevent="save" x-ref="dnd"
class="relative flex flex-col text-gray-400 border border-gray-200 border-dashed rounded cursor-pointer">
<input accept="images/*" type="file" multiple wire:model="photo"
class="absolute inset-0 z-50 w-full h-full p-0 m-0 outline-none opacity-0 cursor-pointer"
x-on:change="addFiles($event)"
x-on:dragover="$refs.dnd.classList.add('border-blue-400'); $refs.dnd.classList.add('ring-4'); $refs.dnd.classList.add('ring-inset');"
x-on:dragleave="$refs.dnd.classList.remove('border-blue-400'); $refs.dnd.classList.remove('ring-4'); $refs.dnd.classList.remove('ring-inset');"
x-on:drop="$refs.dnd.classList.remove('border-blue-400'); $refs.dnd.classList.remove('ring-4'); $refs.dnd.classList.remove('ring-inset');"
title="" />
<div class="flex flex-col items-center justify-center py-10 text-center">
<svg class="w-6 h-6 mr-1 text-current-50" 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="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<p class="m-0">Drag your files here or click in this area.</p>
</div>
</form>
<template x-if="files.length > 0">
<div class="grid grid-cols-2 gap-4 mt-4 md:grid-cols-6" x-on:drop.prevent="drop($event)"
x-on:dragover.prevent="$event.dataTransfer.dropEffect = 'move'">
<template x-for="(_, index) in Array.from({ length: files.length })">
<div class="relative flex flex-col items-center overflow-hidden text-center bg-gray-100 border rounded cursor-move select-none"
style="padding-top: 100%;" x-on:dragstart="dragstart($event)" x-on:dragend="fileDragging = null"
:class="{ 'border-blue-600': fileDragging == index }" draggable="true" :data-index="index">
<button class="absolute top-0 right-0 z-50 p-1 bg-white rounded-bl focus:outline-none"
type="button" x-on:click="remove(index)">
<svg class="w-4 h-4 text-gray-700" 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="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
<span x-text="index"></span>
</button>
<template x-if="files[index].type.includes('image/')">
<img class="absolute inset-0 z-0 object-cover w-full h-full border-4 border-white preview"
x-bind:src="loadFile(files[index])" />
</template>
<div class="absolute bottom-0 left-0 right-0 flex flex-col p-2 text-xs bg-white bg-opacity-50">
<span class="w-full font-bold text-gray-900 truncate"
x-text="files[index].name">Loading</span>
<span class="text-xs text-gray-900" x-text="humanFileSize(files[index].size)">...</span>
</div>
<div class="absolute inset-0 z-40 transition-colors duration-300"
x-on:dragenter="dragenter($event)" x-on:dragleave="fileDropping = null"
:class="{ 'bg-blue-200 bg-opacity-80': fileDropping == index && fileDragging != index }">
</div>
</div>
</template>
</div>
</template>
</div>
<script src="https://unpkg.com/create-file-list"></script>
<script>
function dataFileDnD() {
return {
files: [],
fileDragging: null,
fileDropping: null,
humanFileSize(size) {
const i = Math.floor(Math.log(size) / Math.log(1024));
return (
(size / Math.pow(1024, i)).toFixed(2) * 1 +
" " + ["B", "kB", "MB", "GB", "TB"][i]
);
},
remove(index) {
let files = [...this.files];
files.splice(index, 1);
this.files = createFileList(files);
},
drop(e) {
let removed, add;
let files = [...this.files];
removed = files.splice(this.fileDragging, 1);
files.splice(this.fileDropping, 0, ...removed);
this.files = createFileList(files);
this.fileDropping = null;
this.fileDragging = null;
},
dragenter(e) {
let targetElem = e.target.closest("[draggable]");
this.fileDropping = targetElem.getAttribute("data-index");
},
dragstart(e) {
this.fileDragging = e.target
.closest("[draggable]")
.getAttribute("data-index");
e.dataTransfer.effectAllowed = "move";
},
loadFile(file) {
const preview = document.querySelectorAll(".preview");
const blobUrl = URL.createObjectURL(file);
preview.forEach(elem => {
elem.onload = () => {
URL.revokeObjectURL(elem.src); // free memory
};
});
return blobUrl;
},
addFiles(e) {
const files = createFileList([...this.files], [...e.target.files]);
this.files = files;
}
};
}
</script>
</div>
I am running into a very strange issue where I have a chatroom that should update whenever a new message is posted. Instead when I add a new message the x-data is getting updated and I can see the message there but the x-for doesnt seem to run and it never appears on the frontend. Then when I enter another message the previous message shows up on the frontend but the latest message does not show even though the x-data has been updated to reflect it.
Here is the code below:
<div
x-data="{{ json_encode(['messages' => $messages, 'messageBody' => '']) }}"
x-init="
Echo.join('chat.2')
.listen('ChatSent', (e) => {
#this.call('incomingMessage', e)
console.log(e)
})
">
<div
class="wow fadeInUp mb-10 rounded-md bg-light-bg dark:bg-dark"
data-wow-delay="0s"
>
<h3
class="border-b border-body-color border-opacity-10 py-4 px-8 text-lg font-semibold text-black dark:border-white dark:border-opacity-10 dark:text-white"
>
Chat
</h3>
<div id="chat-window" class="relative w-full p-3 overflow-y-auto h-[14rem]">
<ul class="space-y-2">
<template
x-for="message in messages"
:key="message.id"
>
<div>
<template x-if="message.user_id == {{ Auth::user()->id }}">
<li class="flex justify-end">
<div class="relative max-w-xl px-4 py-2 text-black dark:text-white bg-gray-100 dark:bg-black rounded shadow">
<span class="block" x-text="message.body"></span>
</div>
</li>
</template>
<template x-if="message.user_id != {{ Auth::user()->id }}">
<li class="flex justify-start">
<div class="relative max-w-xl px-4 py-2 text-black dark:text-white bg-blue-100 dark:bg-[#1e2a78] rounded shadow">
<span class="block" x-text="message.body"></span>
</div>
</li>
</template>
</div>
</template>
</ul>
</div>
<div class="flex items-center justify-between w-full p-3 border-t border-gray-300">
<input
#keydown.enter="
#this.call('sendMessage', messageBody)
messageBody = ''
"
x-model="messageBody"
type="text"
placeholder="Message"
class="block w-full py-2 pl-4 mx-3 bg-gray-100 dark:bg-black rounded-full outline-none focus:text-gray-700 dark:focus:text-white dark:text-white"
name="message" required />
<button
#click="
#this.call('sendMessage', messageBody)
messageBody = ''
">
<svg class="w-5 h-5 text-black dark:text-white origin-center transform rotate-90" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20" fill="currentColor">
<path
d="M10.894 2.553a1 1 0 00-1.788 0l-7 14a1 1 0 001.169 1.409l5-1.429A1 1 0 009 15.571V11a1 1 0 112 0v4.571a1 1 0 00.725.962l5 1.428a1 1 0 001.17-1.408l-7-14z" />
</svg>
</button>
</div>
#error('messageBody')
<div class="w-full p-2 text-center">
<span class="text-red-500">Message is required!</span>
</div>
#enderror
</div>
<div
class="wow fadeInUp mb-10 rounded-md bg-light-bg dark:bg-dark"
data-wow-delay="0s">
<h3
class="border-b border-body-color border-opacity-10 py-4 px-8 text-lg font-semibold text-black dark:border-white dark:border-opacity-10 dark:text-white"
>
Active Players
</h3>
<ul class="flex flex-wrap py-6 px-8">
#forelse($here as $authData)
<li>
<a
href="javascript:void(0)"
class="text-body-color-3 mr-3 mb-3 inline-flex items-center justify-center rounded-full border-[.5px] border-body-color bg-body-color bg-opacity-10 py-2 px-4 hover:border-primary hover:bg-primary hover:text-white dark:border-[#363D68] dark:bg-[#272E5C] dark:text-white dark:hover:border-primary dark:hover:bg-primary dark:hover:text-white"
>
{{ $authData['name'] }}
</a>
</li>
#empty
#endforelse
</ul>
</div>
</div>
I figure it has to be something simple I am missing and hopefully someone can point me in the right direction.
EDIT to include Livewire code:
<?php
namespace App\Http\Livewire;
use App\Events\ChatSent;
use App\Models\Chat;
use App\Models\Games;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
class Chatbox extends Component
{
public $game_id, $game, $chats;
public $here = [];
public $messages = [];
public function getListeners()
{
$game_id = $this->game_id;
return [
"echo-presence:chat.{$game_id},here" => 'here',
"echo-presence:chat.{$game_id},joining" => 'joining',
"echo-presence:chat.{$game_id},leaving" => 'leaving',
];
}
public function render()
{
return view('games.components.chatbox');
}
public function mount()
{
$this->game = Games::find($this->game_id);
$this->messages = Chat::
where('games_id', $this->game_id)
->with('user')
->latest()
->limit(30)
->get()
->reverse()
->values()
->toArray();
}
public function sendMessage($body)
{
if (! $body) {
$this->addError('messageBody', 'Message body is required.');
return;
}
$message = Auth::user()->chats()->create([
'body' => $body,
'games_id' => $this->game_id,
]);
$message->load('user');
broadcast(new ChatSent($message, $this->game))->toOthers();
$myMessage = $message->toArray();
$this->dispatchBrowserEvent('update-chat');
array_push($this->messages, $myMessage);
}
/**
* #param $message
*/
public function incomingMessage($message)
{
// get the hydrated model from incoming json/array.
$message = Chat::with('user')->find($message['id']);
array_push($this->messages, $message);
$this->dispatchBrowserEvent('update-chat');
}
/**
* #param $data
*/
public function here($data)
{
$this->here = $data;
}
/**
* #param $data
*/
public function leaving($data)
{
$here = collect($this->here);
$firstIndex = $here->search(function ($authData) use ($data) {
return $authData['id'] == $data['id'];
});
$here->splice($firstIndex, 1);
$this->here = $here->toArray();
}
/**
* #param $data
*/
public function joining($data)
{
$this->here[] = $data;
}
}
This code is a part of the View file connected with the Livewire component.
How to prevent using a parameter when before a button clicked?
View
...
#foreach ($babies as $baby)
...
<div
class="flex justify-between w-11-12 py-1 mb-1 ml-2 leading-6 text-sm font-medium ext-left text-white uppercase transition rounded shadow ripple hover:shadow-lg hover:bg-blue-800 focus:outline-none">
<button wire:click="setAte({{ $baby, $ate = 0 }})"
class="flex w-1-3 mr-1 px-2 text-xs font-medium text-center text-white uppercase transition rounded shadow ripple hover:shadow-lg hover:bg-pink-800 focus:ring-ring-600 {{ $baby['ate'] == 0 ? "bg-blue-500" : "bg-red-500" }}">
S</button>
<button wire:click="setAte({{ $baby, $ate = 1 }})"
class="flex w-1-3 mr-1 px-2 text-xs font-medium text-center text-white uppercase transition rounded shadow ripple hover:shadow-lg hover:bg-pink-800 focus:ring-pink-600 {{ $baby['ate'] == 1 ? "bg-blue-500" : "bg-red-500"}}">
M</button>
<button wire:click="setAte({{ $baby, $ate = 2}})"
class="flex w-1-3 px-2 text-xs font-medium text-center text-white uppercase transition rounded shadow ripple hover:shadow-lg hover:bg-pink-800 focus:ring-pink-600 {{ $baby['ate'] == 2 ? "bg-blue-500" : "bg-red-500" }}">
L</button>
<div>{{ $baby['ate'] }}</div> {{-- <---check code --}}
</div>
#endforeach
...
Component
public function setAte($baby, $ate)
{
$baby['ate'] = $ate;
$selectedBaby = Baby::find($baby['id']);
$selectedBaby->save();
}
Error
Illuminate\Contracts\Container\BindingResolutionException
Unable to resolve dependency [Parameter #1 [ $ate ]] in class App\Http\Livewire\Classroom\BabyStatus
Solution 1
//Component
public $baby;
protected $rules = [
'baby.ate' => 'required|int|min:0|max:2'
];
public function updateAte($ate)
{
$this->baby->ate = $ate;
$this->baby->save();
}
//View
<button wire:model="baby" wire:click="updateAte(0)"
class="flex w-1-3 mr-1 px-2 text-xs font-medium text-center text-white uppercase transition rounded shadow ripple hover:shadow-lg hover:bg-pink-800 focus:ring-ring-600 {{ $baby['ate'] == 0 ? "bg-blue-500" : "bg-red-500"}}">S</button>
<button wire:model="baby" wire:click="updateAte(1)"
class="flex w-1-3 mr-1 px-2 text-xs font-medium text-center text-white uppercase transition rounded shadow ripple hover:shadow-lg hover:bg-pink-800 focus:ring-pink-600 {{ $baby['ate'] == 1 ? "bg-blue-500" : "bg-red-500"}}">M</button>
<button wire:model="baby" wire:click="updateAte(2)"
class="flex w-1-3 px-2 text-xs font-medium text-center text-white uppercase transition rounded shadow ripple hover:shadow-lg hover:bg-pink-800 focus:ring-pink-600 {{ $baby['ate'] == 2 ? "bg-blue-500" : "bg-red-500" }}">L</button>
That's all, thank you #Unflux.
I would be inclined to refactor what you have and make each baby a separate livewire component.
App\Http\Livewire\Baby.php
class Baby extends Component
{
// your instance of a baby
public $baby;
// required to allow updating of the baby properties
protected $rules = [
'baby.ate' => 'required|int|min:0|max:2'
];
public function render()
{
return view('livewire.baby');
}
// you can set the value of properties here if you want
public function mount()
{
// for example:
//$this->baby->ate = -100;
}
// when the value of ate is updated from the view
// update the baby model
public function updatedBaby()
{
$this->baby->save();
}
}
resoures\views\livewire\baby.blade.php
<div class="p-4 m-4">
<h4>Baby Component - ate: {{ $baby->ate }}</h4>
<div class="flex justify-between p-4 m-4">
<button wire:click="$set('baby.ate', 0)"
class="text-white px-2 rounded {{ $baby->ate === 0 ? "bg-blue-500" : "bg-red-500" }}">S
</button>
<button wire:click="$set('baby.ate', 1)"
class="text-white px-2 rounded {{ $baby->ate === 1 ? "bg-blue-500" : "bg-red-500" }}">M
</button>
<button wire:click="$set('baby.ate', 2)"
class="text-white px-2 rounded {{ $baby->ate === 2 ? "bg-blue-500" : "bg-red-500" }}">L
</button>
</div>
</div>
Note: The use of === in the above. Prevents null or similar values being incorrectly determined as equal to 0.
Then in your view:
#foreach($babies as $baby)
#livewire("baby", ["baby" => $baby]) // render your single baby component
#endforeach
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