So, I have created a Laravel controller with pagination. The code inside my Vue file is the following
<div class="flex justify-between flex-wrap">
<div v-for="kink in kinks.data" :key="kink.id" :value="kink.name">
<button type="button" class="m-1 my-2 inline-flex items-center px-3.5 py-2 border border-transparent text-sm leading-4 font-medium rounded-full shadow-sm text-white bg-gray-600 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500"> {{ kink.name }}</button>
</div>
</div>
<div class="flex justify-between">
<ArrowLeftIcon type="button" :href="kinks.next_page_url" class="m-2 inline-flex items-center px-2 py-1 h-7 rounded-full border border-transparent text-sm leading-4 font-medium shadow-sm text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 "></ArrowLeftIcon>
<ArrowRightIcon type="button" :href="kinks.last_page_url" class="m-2 inline-flex items-center px-2 py-1 h-7 rounded-full border border-transparent text-sm leading-4 font-medium shadow-sm text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500"></ArrowRightIcon>
</div>
The arrow buttons should change the v-for data based on the active page. I have NEVER done this before and I do not want to use some cheap npm package when I just need next and previous.
IDEALLY, if someone is on page 1, and they click previous, it should go to the last page and the same with last page next should go to page 1
How do you implement this?
The data object inside vue from the pagination provides the following:
kinks:Object
current_page:1
data:Array[13]
first_page_url:"http://localhost:8000/kinks?page=1"
from:1
last_page:5
last_page_url:"http://localhost:8000/kinks?page=5"
links:Array[7]
next_page_url:"http://localhost:8000/kinks?page=2"
path:"http://localhost:8000/kinks"
per_page:13
prev_page_url:null
to:13
total:63
ok so you will want to change the way your buttons work then. e.g. add a #click method to them instead of a href
example
<button #click="previousLink">
...icon
</button>
<script>
export default {
methods: {
previousLink() {
if (this.prev_page_url === null) {
window.location.href = this.last_page_url;
} else {
window.location.href = this.prev_page_url;
}
}
}
}
</script>
Related
I am trying to add the conditional rendering for user dropdown, so once the user is signed in, and when they click the account icon, the page will show the dropdown menu of that user. i am using useSelector to track the user state, right now, the dropdown menu is shown under the icon once the user sign in.... i want to add the onclick functionality on that, so they need to click the account icon, and then the menu will pop up, anyone know how to add that?
export default function Example() {
const user = useSelector((state) => state.user);
return (
<div className="bg-white">
<div className="ml-auto flex items-center">
<div className="hidden relative lg:flex lg:flex-1 lg:items-center lg:justify-end lg:space-x-6">
<UserCircleIcon
className="h-6 w-6 flex-shrink-0 text-gray-400 group-hover:text-gray-500"
aria-hidden="true"
/>
{user && (
<div className="w-24 z-10 rounded-md bg-white py-1 shadow-lg flex flex-col absolute mt-36 right-0 ring-1 ring-black ring-opacity-5 focus:outline-none">
<p className="bg-gray-50 flex items-center gap-3 cursor-pointer hover:bg-slate-100 trainstion-all duration-100 ease-in-out px-4 py-2 text-sm text-gray-700">
Profile
</p>
<p className="bg-gray-50 flex items-center gap-3 cursor-pointer hover:bg-slate-100 trainstion-all duration-100 ease-in-out px-4 py-2 text-sm text-gray-700">
Settings
</p>
<p className="bg-gray-50 flex items-center gap-3 cursor-pointer hover:bg-slate-100 trainstion-all duration-100 ease-in-out px-4 py-2 text-sm text-gray-700">
Signout
</p>
</div>
)}
</div>
If I understand your question correctly, what you need an additional local state to keep track of whether the user clicked on the "user" icon. You will need to pass that extra condition to your conditional rendering write a function to change the state to true once the user click on the user icon.
export default function Example() {
const user = useSelector((state) => state.user);
const [isOpen, setIsOpen] = useState(false); <--- new local state/condition ---<<
const handleOpenUserMenu = () => setIsOpen(true); <--- set function ---<<
return (
<div className="bg-white">
<div className="ml-auto flex items-center">
<div className="hidden relative lg:flex lg:flex-1 lg:items-center lg:justify-end lg:space-x-6">
<UserCircleIcon
className="h-6 w-6 flex-shrink-0 text-gray-400 group-hover:text-gray-500"
aria-hidden="true"
onClick={handleOpenUserMenu} <--- pass the set function here ---<<
/>
{user && isOpen && ( <--- add the extra condition here ---<<
<div className="w-24 z-10 rounded-md bg-white py-1 shadow-lg flex flex-col absolute mt-36 right-0 ring-1 ring-black ring-opacity-5 focus:outline-none">
<p className="bg-gray-50 flex items-center gap-3 cursor-pointer hover:bg-slate-100 trainstion-all duration-100 ease-in-out px-4 py-2 text-sm text-gray-700">
Profile
</p>
<p className="bg-gray-50 flex items-center gap-3 cursor-pointer hover:bg-slate-100 trainstion-all duration-100 ease-in-out px-4 py-2 text-sm text-gray-700">
Settings
</p>
<p className="bg-gray-50 flex items-center gap-3 cursor-pointer hover:bg-slate-100 trainstion-all duration-100 ease-in-out px-4 py-2 text-sm text-gray-700">
Signout
</p>
</div>
)}
</div>
</div>
</div>
);
}
I have a form with several input fields and some of them render conditionally using AlpineJS x-if, those elements have wire:model data, but when the elements rendered conditionally the model binding seems not working. I tried to print the variable on the element but it doesn't work. Without x-if it works fine.
<div class="form-check" >
<input class="form-check-input appearance-none rounded-full h-4 w-4 border border-gray-300 bg-white checked:bg-[#60D619] checked:border-[#60D619] focus:outline-none transition duration-200 mt-1 align-top bg-no-repeat bg-center bg-contain float-left mr-2 cursor-pointer" type="radio" id="company" wire:model="isCompany" #click="open = true" value="true">
<label class="form-check-label inline-block px-1 text-sm text-gray-600" for="company">
Yes, I'm a company.
</label>
</div>
<div class="form-check">
<input class="form-check-input appearance-none rounded-full h-4 w-4 border border-gray-300 bg-white checked:bg-[#60D619] checked:border-[#60D619] focus:outline-none transition duration-200 mt-1 align-top bg-no-repeat bg-center bg-contain float-left mr-2 cursor-pointer" type="radio" id="person" wire:model="isCompany" #click="open = false" value="false">
<label class="form-check-label inline-block px-1 text-sm text-gray-600" for="person">
No. I'm not a company.
</label>
</div>
<div class="py-1" x-show="open" x-transition>
<span class="px-1 text-sm text-gray-600">Company Name</span>
<input wire:model.lazy="companyName" placeholder="" type="text"
class="text-md block px-3 py-2 rounded-lg w-full
bg-white border-2 border-gray-300 placeholder-gray-600 shadow-md focus:placeholder-gray-500 focus:bg-white focus:border-gray-600 focus:outline-none">
</div>
<div class="py-1" x-show="!open" x-transition>
<span class="px-1 text-sm text-gray-600">User Name</span>
<input wire:model="name" placeholder="" type="text"
class="text-md block px-3 py-2 rounded-lg w-full
bg-white border-2 border-gray-300 placeholder-gray-600 shadow-md focus:placeholder-gray-500 focus:bg-white focus:border-gray-600 focus:outline-none">
</div>
<div class="py-1" x-show="!open" x-transition>
<span class="px-1 text-sm text-gray-600">First Name</span>
<input wire:model="fullName" placeholder="" type="text"
class="text-md block px-3 py-2 rounded-lg w-full
bg-white border-2 border-gray-300 placeholder-gray-600 shadow-md focus:placeholder-gray-500 focus:bg-white focus:border-gray-600 focus:outline-none">
</div>
When x-show uses the issue goes away but the unnecessary input fields are not cleared. I don't want those data to be saved on the database. Is this because x-show only toggles the visibility of the elements and x-if completely removes the element from the DOM? Or is there a way to reset the values of the input fields when visibility is toggled using x-show?
x-if indeed removes the element, while x-show only hides it.
wire:model only works if it's loaded in with Livewire. Else Livewire doesn't "know" those fields exist, and thus can't add an event listener to detect change/input/etc. Therefore, you want to do what #Bennett already mentioned, and only hide the inputs, and clear the fields.
You can use $wire to directly clear the input. Otherwise, you will have to dispatch a change or input event on the input field (change for lazy, input for non-lazy).
I am a beginner to Tailwind CSS. And I am finding it difficult to create a button design as shown in the picture in tailwind Css
So I want to display that little bar on the right when the individual section like eg. Home,Trends,Feed are pressed. So can you please help me out with it. I want the answer in tailwind css.
Here is the code:
<div className="flex">
<div className="w-72 bg-white text-gray-100 shadow-lg">
<div class="flex h-full flex-col p-7 pl-8 text-sm">
<div class="relative flex w-full items-center justify-between">
<a class="flex space-x-5 py-5 text-slate-800">
<MusicNoteIcon class="h-5 w-5"></MusicNoteIcon>
<p class="font-semibold">Sovereignty Kingdom</p>
</a>
<button class="delay-50 absolute right-[3px] h-10 cursor-pointer rounded-full p-2 text-slate-800 transition duration-200 ease-in-out hover:scale-110 hover:bg-black hover:text-white">
<SwitchHorizontalIcon class="h-5 w-5"></SwitchHorizontalIcon>
</button>
</div>
<nav className="delay-50 my-2 flex cursor-pointer items-center space-x-3 rounded-lg p-3 text-slate-800 transition duration-200 ease-in-out hover:-translate-y-1 hover:scale-110 hover:bg-black hover:text-white">
<HomeIcon className="h-5 w-5" />
<p>Home</p>
</nav>
<nav className="delay-50 my-2 flex cursor-pointer items-center space-x-3 rounded-lg p-3 text-slate-800 transition duration-200 ease-in-out hover:-translate-y-1 hover:scale-110 hover:bg-black hover:text-white">
<TrendingUpIcon className="h-5 w-5" />
<p>Trends</p>
</nav>
<nav className="delay-50 duration-2 cursor-pointer00 my-2 flex cursor-pointer items-center space-x-3 rounded-lg p-3 text-slate-800 transition ease-in-out hover:-translate-y-1 hover:scale-110 hover:bg-black hover:text-white">
<RssIcon className="h-5 w-5" />
<p>Feed</p>
</nav></div>
</div>
</div>```
I'm not sure if this is the only solution, but this worked for me:
The first thing I did was define an array for the buttons group :
const elements=[
{name:'Home',ico:faHome}, //I'm using font awesome Icons,you can use yours
{name:'Trend',ico:faFireAlt},
{name:'Feed',ico:faFeed}
]
then I defined a state so that I know which button was clicked like
//(-1) is the button id, default (-1) so that the bar won't render by default
const [clickedId, setClickedId] = useState(-1);
Here is the full code:
<div className='flex m-14 w-72 '>
<div className="w-full bg-white text-gray-100 shadow-lg">
<div className="flex h-full flex-col p-7 pl-8 text-sm">
<div className="relative flex w-full items-center justify-between">
<a className="flex space-x-5 py-5 text-slate-800">
<div className="h-5 w-5 bg-teal-800 rounded-full"></div>
<p className="font-semibold">Sovereignty Kingdom</p>
</a>
<button className="delay-50 absolute right-[3px] h-10 cursor-pointer rounded-full p-2 text-slate-800 transition duration-200 ease-in-out hover:scale-110 hover:bg-black hover:text-white">
<div className="h-5 w-5 bg-teal-800 rounded-full"></div>
</button>
</div>
{/* map over the buttons array to render them */}
{elements.map((el,id)=>(
{/* give every button a key */}
<button key={id} name={el.name}
{/* when a button is clicked assign clickedId to the current button id */}
onClick={() => setClickedId(id)}
{/* based on the button id append classes to make the sidebar */}
className={`relative delay-50 my-2 flex cursor-pointer items-center space-x-3 rounded-lg p-3
text-slate-800 transition duration-75 ease-in-out hover:-translate-y-1
hover:scale-110 hover:bg-black hover:text-white
${(id === clickedId) ?`after:w-1 after:h-12 after:bg-black after:rounded-full after:absolute after:-right-7
hover:after:transition hover:after:duration-75 hover:after:-right-4 hover:after:ease-in-out`:'' }`}>
<FontAwesomeIcon className='h-5 w-5 ' icon={el.ico}/>
<p>{el.name}</p>
</button>
))}
</div>
</div>
</div>
or check it Live on codesandbox.
The pagination in my project displays as shown below:
And renders the following HTML:
<nav role="navigation" aria-label="Pagination Navigation" class="flex items-center justify-between">
<div class="flex justify-between flex-1 sm:hidden">
<span
class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default leading-5 rounded-md">
« Précédent
</span>
<a href="http://127.0.0.1:8000/clients?page=2"
class="relative inline-flex items-center px-4 py-2 ml-3 text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 rounded-md hover:text-gray-500 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150">
Suivant »
</a>
</div>
<div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
<div>
<p class="text-sm text-gray-700 leading-5">
Showing
<span class="font-medium">1</span>
to
<span class="font-medium">10</span>
of
<span class="font-medium">11</span>
results
</p>
</div>
<div>
<span class="relative z-0 inline-flex shadow-sm rounded-md">
<span aria-disabled="true" aria-label="« Précédent">
<span
class="relative inline-flex items-center px-2 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default rounded-l-md leading-5"
aria-hidden="true">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z"
clip-rule="evenodd" />
</svg>
</span>
</span>
<span aria-current="page">
<span
class="relative inline-flex items-center px-4 py-2 -ml-px text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default leading-5">1</span>
</span>
<a href="http://127.0.0.1:8000/clients?page=2"
class="relative inline-flex items-center px-4 py-2 -ml-px text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 hover:text-gray-500 focus:z-10 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150"
aria-label="Go to page 2">
2
</a>
<a href="http://127.0.0.1:8000/clients?page=2" rel="next"
class="relative inline-flex items-center px-2 py-2 -ml-px text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-r-md leading-5 hover:text-gray-400 focus:z-10 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-500 transition ease-in-out duration-150"
aria-label="Suivant »">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd" />
</svg>
</a>
</span>
</div>
</div>
</nav>
Which in an isolated environment from my project results in:
Last time I seen the pagination in my project is a month ago, after that I:
Upgraded from Laravel 8 to Laravel 9.
Upgraded from Tailwind 2.6^ to Tailwind 3^.
Upgraded Mix
Deleted some of the components that comes by default with Breeze scafolding .
Edit
When I export the pagination views to resources\views using:
php artisan vendor:publish --tag=laravel-pagination
Then run:
npm run dev
The pagination is fixed!
But When I delete resources\views\vendor\pagination and rerun npm run dev, The pagination is broken again!
This makes me think that Mix is missing the CSS classes used in the pagination element. which wasn't the case before I upgrade.
So how can I fix this? (exporting feels like a patch and not a solution).
By going back to the guide Upgrading your Tailwind CSS projects from v2 to v3 I noticed:
If you weren’t already using the purge option in your project, it’s crucial that you configure your template paths now or your compiled CSS will be empty.
I fixed the issue by referencing "./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php" in tailwind.config.js and running npm run dev
const defaultTheme = require("tailwindcss/defaultTheme");
module.exports = {
content: [
"./resources/**/*.blade.php",
"./resources/**/*.js",
"./resources/**/*.vue",
"./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php",
],
// ...
}
Checking my upgrade commit
Because I blindly followed the "Laravel with Tailwind 3 docs/posts" without noticing that they did not consider the Pagination.
I have two buttons in tailwindcss in my
<div class="flex flex-row">
<button class="-ml-px relative inline-flex items-center space-x-2 px-4 py-4 border border-blue-300 text-sm font-medium rounded-l-md text-white bg-blue-500 hover:bg-blue-600 focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-blue-500">
<span>Add</span>
</button>
<button class="-ml-px relative inline-flex items-center space-x-2 px-4 py-4 border border-gray-300 text-sm font-medium text-gray-900 bg-gray-50 hover:bg-gray-100 focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-blue-500">
<span>Set</span>
</button>
</div>
one button is blue and other is grey.
I want to switch colour when I click on Set Button and also same when I click back to Add button again.
As I mentioned, Livewire is for interaction with backend code. If you want to style frontend elements following frontend interaction, use a JS Framework like AlpineJS or plain CSS.
If you really just want to change focus color, you can go with a variation of #Digvijay's answer:
<div class="flex space-x-4">
<button class="flex px-4 py-2 bg-gray-100 text-gray-900 cursor-pointer hover:bg-blue-200 focus:text-blue-700 focus:bg-blue-200 focus:outline-none focus:ring-blue-600" tabindex="1">Add</button>
<button class="flex px-4 py-2 bg-gray-100 text-gray-900 cursor-pointer hover:bg-blue-200 focus:text-blue-700 focus:bg-blue-200 focus:outline-none focus:ring-gray-600" tabindex="2">Set</button>
</div>
(see https://play.tailwindcss.com/mwspfpsTuU)
If you want the colors to stick even after the focus is lost, you may use something like this with AlpineJS:
<div x-data="{ highlightedButton: '' }" class="flex space-x-4">
<button #click="highlightedButton='add'" class="flex px-4 py-2 bg-gray-100 text-gray-900 hover:bg-blue-200" :class="{'bg-blue-400': highlightedButton === 'add'}" tabindex="1">Add</button>
<button #click="highlightedButton='set'" class="flex px-4 py-2 bg-gray-100 text-gray-900 hover:bg-blue-200" :class="{'bg-blue-400': highlightedButton === 'set'}" tabindex="2">Set</button>
</div>
And finally if you keep track of the Add / Set state in the Livewire component anyways (which is hard to tell because there is no livewire code in your markup at all), then do it like #AliAli described in his answer. :-)
Edit:
If anyone came to this answer, this is a solution when storing the button state is needed, in other cases, you should follow #Lupinity Labs answer.
You can use Livewire event listeners to change the frontend.
First, declare variables inside the Livewire PHP model like:
public $isSetClicked = false;
public $isAddClicked = false;
Then decalre functions to handle the onClick event:
public function SetClicked()
{
//this will give you toggling behavior
$this->isSetClicked == false ? $this->isSetClicked = true : $this->isSetClicked = false;
}
and declare the AddClicked the same way.
Then inside your Livewire template add the events to the buttons like:
<button wire:click="SetClicked()" class="{{$isSetClicked ? "color-class" : "other-color-class"}} the rest of your css classes">
To toggle HTML attributes with livewire, for example class, id, href and so on you have to work with AlpineJS inside livewire (docs). For example you want to change some element CSS class attribute by changing a some internal state (model) inside your livewire component. For example by clicking a some link.
/app/Http/Livewire/YourLivewireComponent.php
<?php
namespace App\Http\Livewire;
use Livewire\Component;
class YourLivewireComponent extends Component
{
public $classChanged = false;
public function render()
{
return view('livewire.your-liveweire-component');
}
public function myClickFunction()
{
$this->classChanged = true;
}
}
/resources/views/livewire/your-livewire-component.blade.php
Click me
<div x-data="{ alpine_class_changed: #entangle('classChanged') }" class="some classes" x-bind:class="alpine_class_changed ? 'my_add_class' : ''">some text</div>
/resources/views/somelaraveltemplate.blade.php
<p>some HTML code</p>
#livewire('your-liveweire-component')
You will need to use tabindex. Checkout focus change on button working example.
<div class="flex space-x-4">
<div class="flex px-4 py-2 bg-blue-600 text-blue-100 cursor-pointer hover:bg-blue-700 focus:text-blue-700 focus:bg-blue-200 focus:outline-none focus:ring-blue-600" tabindex="1">Add</div>
<div class="flex px-4 py-2 bg-gray-100 text-gray-600 cursor-pointer hover:bg-gray-200 focus:text-gray-100 focus:bg-gray-600 focus:outline-none focus:ring-gray-600" tabindex="1">Set</div>
</div>