I've been watching a comment livewire tutorial from codecoure. Everything worked fine till a form that will store the comment is not going through. I tried dd, but I get nothing. In the url after the slug it says comment=whateverItyped. i've been using this tutorial in a story posting board, but I'm clueless where the error is. I've even copied and pasted the exact same form and method but nothing goes through the form.
The form:
<div class="min-w-0 flex-1">
<form wire:submit.prevent="postComment">
<div>
<label for="comment" class="sr-only">Comment body</label>
<textarea id="comment" name="comment" rows="3"
class="shadow-sm block w-full focus:ring-blue-500 focus:border-blue-500 border-gray-300 rounded-md #error('newCommentState.body') border-red-500 #enderror"
placeholder="Write something"
wire:model.defer="newCommentState.body">
</textarea>
#error('newCommentState.body')
<p class="mt-2 text-sm text-red-500">{{ $message }}</p>
#enderror
</div>
<div class="mt-3 flex items-center justify-between">
<button type="submit" class="inline-flex items-center justify-center px-4 py-2 border border-transparent font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
Comment
</button>
</div>
</form>
</div>
Since I'm clueless where this error is. I don't know what more I should post than the form. There is anohter method that gets the comments, and that works fine. I think it is something with the post request but I'm unsure since I'm new to livewire
namespace App\Http\Livewire;
use Livewire\Component;
class Comments extends Component
{
public $model;
public function postComment()
{
$this->validate([
'newCommentState.body' => 'required'
]);
$comment = $this->model->comments()->make($this->newCommentState);
$comment->user()->associate(auth()->user());
$comment->save();
$this->newCommentState = [
'body' => ''
];
$this->goToPage(1);
}
public function render()
{
$comments = $this->model
->comments()
->with('user', 'children.user', 'children.children')
->parent()
->latest()
->get();
return view('livewire.comments', [
'comments' => $comments
]);
}
}
It seems you are using $newCommentState, but never declares it.
Add a new attribute public $newCommentState;.
I would also create a method like that:
// this will initialize $newCommentState
public function mount() {
$this->newCommentState = [
'body' => ''
];
}
Related
I am trying to display all entries of a database in the frontend, which worked fine until I needed to get Post via a join with another table.
Now when I loop through the posts I get a lot of duplicate outputs and I cant get my head around how to accomplish the correct output.
Here is my controller code:
public function getApplications()
{
$query = Bewerbungen::query();
$bewerbungen = $query->orderBy('Bewerbung_ID')->get();
$stellenanzeigen_name = Post::join('bewerbungens', 'posts.id', '=', 'bewerbungens.Stellenanzeigen_ID')
->get(['bewerbungens.Stellenanzeigen_ID' , 'posts.Titel']);
$data = [
'bewerbungen' => $bewerbungen,
'stellen_names' => $stellenanzeigen_name,
];
return view('bewerbungen_overview')->with($data);
}
Here is my blade code:
#foreach($bewerbungen as $bewerbung)
#foreach($stellen_names as $stellen_name)
#if($bewerbung->Stellenanzeigen_ID === $stellen_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-2 pl-6 mt-3"> {{ $stellen_name->Titel }}</div>
<div class="pt-4 pl-8 font-medium text-xl font-bold font-serif">
Kontakt: {{ $bewerbung->bewerber_email }}</div>
</div>
</div>
#endif
#endforeach
#endforeach
So pretty much I am checking if the the ID's match and if they do I want to display the data. but I get a lot of duplicate outputs.
I thought about ending the loop when the number of database entries is reached, but I don't know if that's possible /makes sense.
I am fairly new to laravel so any help appreciated :)
Edit: Here is a picture of the output when I dd($data)
https://i.stack.imgur.com/ba7pc.png
This has the right amount of entries and the correct data
hello guys I'm new to laravel and livewire please kindly assist, post request not going through , if i click on the submit nothing is happening, I'm not getting error either, I have added the livewire script in my app.blade.php and it's rendering properly
Post Create form
<div>
<div class="p-4 mx-auto mt-3 bg-gray-100 md:p-8 md:w-4/5 md:mt-0">
<h1 class="mb-3 text-xl font-semibold text-gray-600">New post</h1>
<form wire:submit.prevent="createPost" action="#" class="px-4 py-6 space-y-4">
<div class="overflow-hidden bg-white rounded-md shadow">
<div class="px-4 py-3 space-y-8 sm:p-6">
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-3">
<input class="w-full" type="text"
wire:model="post.title" placeholder="Post title" />
</div>
</div>
<div class="flex flex-col">
<textarea id="body" rows="4" wire:model="post.body"
class="border-gray-300 rounded-sm form-textarea">
</textarea>
</div>
</div>
<div class="px-4 py-3 text-right bg-gray-50 sm:px-6">
<button type="submit" class="inline-flex justify-center">
post
</button>
</div>
</div>
</form>
</div>
</div>
this is my post create livewire method
<?php
namespace App\Http\Livewire;
use App\Models\Post;
use Livewire\Component;
use Illuminate\Http\Response;
class PostCreate extends Component
{
public $post;
public $points = 10;
public $energy = 1;
public function increment()
{
$this->points++;
}
protected $rules = [
// 'category' => 'required|integer|exists:categories,id',
'title' => 'required|min:4',
'body' => 'required|min:4',
];
public function createPost()
{
if (auth()->check()) {
$this->validate();
$post = Post::create([
'user_id' => auth()->user()->id,
// 'category_id' => $this->category,
'body' => $this->body,
'title' => $this->title,
]);
$users = auth()->user();
$users->increment('points', 10);
session()->flash('success_message', 'Post was added successfully!');
$this->reset();
return redirect()->route('posts.index');
}
// abort(Response::HTTP_FORBIDDEN);
}
public function render()
{
return view('livewire.post-create');
}
}
There are two thing here to note - you don't initialize $this->post and you don't have the proper validation. You need to check for post.title and post.body, and you also need to display the actual errors.
<?php
namespace App\Http\Livewire;
use App\Models\Post;
use Livewire\Component;
class PostCreate extends Component
{
public $post;
public $points = 10;
public $energy = 1;
public function mount()
{
$this->post = new Post;
$this->post->user_id = auth()->id();
}
public function increment()
{
$this->points++;
}
protected $rules = [
// 'category' => 'required|integer|exists:categories,id',
'post.title' => 'required|min:4',
'post.body' => 'required|min:4',
];
public function createPost()
{
if (auth()->check()) {
$this->validate();
$post = $this->post->save();
auth()
->user()
->increment('points', 10);
session()->flash('success_message', 'Post was added successfully!');
$this->reset();
return redirect()->route('posts.index');
}
// abort(Response::HTTP_FORBIDDEN);
}
public function render()
{
return view('livewire.post-create');
}
}
To display the errors from validation, you can add the following snippet in your blade-file,
#if ($errors->any())
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
#endif
Add lazy to the wire.model:
<input class="w-full" type="text" wire:model.lazy="post.title" placeholder="Post title" />
<textarea id="body" rows="4" wire:model.lazy="post.body" class="border-gray-300 rounded-sm form-textarea"></textarea>
I am building a search bar within a webpage. Ideally, user would enter the search text in the search field, and then if there are records found, a search results table would show and display the record found. I am using Laravel Livewire to implement this feature, however, I ran into the problem that the wire:click not firing the event, and any help would be needed!
This is my blade file (resources/livewire/dashboard.blade.php) contains the search bar:
<form>
<label for="searchText" class="block text-xx font-medium text-gray-700">Search Users</label>
<div class="mt-1 flex rounded-md shadow-sm">
<div class="relative flex items-stretch flex-grow focus-within:z-10">
<input type="text" name="searchText" id="searchText"
class="focus:ring-indigo-500 focus:border-indigo-500 block w-full rounded-none rounded-l-md pl-10 sm:text-sm border-gray-300" placeholder="User ID / Email Address / Mobile Number"
wire:model="searchText">
</div>
<button wire:click="search()" class="-ml-px relative inline-flex items-center space-x-2 px-4 py-2 border border-gray-300 text-sm font-medium rounded-r-md text-gray-700 bg-gray-50 hover:bg-gray-100 focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500">
Search
</button>
</div>
</form>
and this is the action defined in the App/Http/Livewire/Dashboard.php file
<?php
namespace App\Http\Livewire;
use Illuminate\Support\Facades\Http;
use Livewire\Component;
class Dashboard extends Component
{
public $stats, $searchText;
public $showResultsTable = false;
protected $accountAPIRootURL = 'https://example.com/api/v2/';
public function render()
{
$response = Http::withHeaders([
'Accept' => 'application/json'
])->get($this->accountAPIRootURL . 'statistics/overview');
if ($response->successful()) {
$stats = $response['data'];
} else {
$stats = [
'total_users' => 0,
'new_users' => 0,
'invitations' => 0,
'new_invitations' => 0,
'requests' => 0,
'new_requests' => 0
];
}
$this->stats = $stats;
$this->searchText = '';
return view('livewire.dashboard');
}
public function search()
{
$response = Http::withHeaders([
'Accept' => 'application'
])->get($this->accountAPIRootURL . 'admin/search', [
'searchText' => $this->searchText
]);
if ($response->successful()) {
$this->showResultsTable = true;
$this->searchText = '';
}
}
}
This is my template.blade.php file, where the #livewire component is called
#extends('layouts.app')
#section('content')
#livewire('dashboard')
#endsection
I am not worrying too much about displaying the result table now because it seems like the search() function is not being triggered when I click on the Search button within the blade. How do I know that, I put a dd() within the search() function and it is not being executed.
I would appreciate any help!
You don't need to use the parenthesis, wire:click="search"
UPDATE: Try this different syntax while you are handle a form in livewire
<form wire:submit.prevent="search">
//.....
<div class="mt-1 flex rounded-md shadow-sm">
//.....
<button class="-ml-px relative inline-flex items-center space-x-2 px-4 py-2 border border-gray-300 text-sm font-medium rounded-r-md text-gray-700 bg-gray-50 hover:bg-gray-100 focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500">
Search
</button>
</div>
</form>
first time using Livewire with Alpine and its a real pain to debug. Alpine console errors are so vague, is there anyway to make them more specific and verbose?
I digress.
I'm updating an array on livewire component which, when not empty, should be showing in the DOM. Everything works and when viewed in the console i can see that the changes are being made. inside the console everything is happening as it should. The trouble is, nothing i happening in the browser!
<div x-data="{ ...data() }" class="overflow-hidden wrapper w-full ">
<div class="flex justify-end w-full relative coins-container space-x-6">
<input id="search-toggle" type="search" pclass="block w-full bg-gray-100 focus:outline-none focus:bg-white focus:shadow text-gray-700 font-bold rounded-lg pl-12 pr-4 py-4 shadow-xl" wire:model.debounce.750ms="searched_term" />
</div>
#if($filtered_variable)
<template>
<div class="mt-1 wrapper">
<div id="search-content" class=" w-full text text-gray-600 rounded-lg overflow-y-auto bg-white shadow-xl" style="max-height: 500px;">
<div id="searchresults" class="h-auto w-full mx-auto">
#foreach ($filtered_variable as $index => $value)
<h1 x-text="{{$value['title']}}"></h1>
#endforeach
</div>
</div>
</div>
</template>
#endif
</div>
Class Searchbar extends Component
{
public $first_array;
public $searched_term;
public $filtered_array;
public function mount()
{
$db_content = Stuff::where(function ($query) {
$query->where('thing', false)
->orWhereNull('thing');
})
->with('variable_eg')
->get();
$this->first_array = $db_content;
$this->searched_term = '';
$this->filtered_array = [];
}
public function render()
{
return view('livewire.searchbar');
}
public function updated($name, $value)
{
if (empty($this->searched_term)) {
return '';
}
$this->filtered_array = array_filter($this->first_array, array($this, 'filter'));
public function filter($element)
{
$title = strtolower($element['title']);
if (strpos($title, $this->searched_term) !== false) {
return true;
}
}
}
inside the console I can see that my alpine/livewire component is receiving the filtered_value just as expected. But nothing is happening on the browser. How can I force rerender?
To update (refresh/rerender) your component you can use a listener
protected $listeners = ['refreshComponent' => '$refresh'];
Then when the refreshComponent event is emitted, it will refresh the component without running any other actions.
There is a Github discussion in the Livewire repo describing this.
Regarding your updating and filter methods (just as a hint):
There are also special methods like updatingFoo, updatedFoo that run before/after an item foo is updating. See the Lifecycle Hooks.
Description
I am type hinting model properties and trying to delete the invitation data. Below is the error which its throwing me back. Please help me with it, as I am unable to spot what is it that I'm missing.
Typed property App\Http\Livewire\Backend\UserManagement\FormComponent\InvitationManagementModal::$invitation must not be accessed before initialization
Stripped-down, copy-pastable code snippets
Livewire\InvitationManagementModal.php
<?php
namespace App\Http\Livewire\Backend\UserManagement\FormComponent;
use Livewire\Component;
use Livewire\WithPagination;
use App\Http\Livewire\Backend\DataTable\WithCachedRows;
use App\Models\Invitation;
class InvitationManagementModal extends Component
{
use WithPagination, WithCachedRows;
public $showInvitationManagementModal = false;
public Invitation $invitation;
protected $listeners = ['manageInvitation'];
public function manageInvitation()
{
$this->showInvitationManagementModal = true;
}
public function deleteInvitation(Invitation $invitation)
{
$this->invitation->delete();
}
public function getInvitationRowsProperty()
{
return $this->cache(function () {
$invitations = Invitation::where('registered_at', null)->paginate(5);
return $invitations;
});
}
public function render()
{
return view('livewire.backend.user-management.form-component.invitation-management-modal', ['invitations' => $this->invitationRows]);
}
}
livewire\invitation-management-modal.blade.php
<div>
<x-modal.stacked wire:model.defer="showInvitationManagementModal" id="scroll-lock">
<x-slot name="title">Manage Invitation</x-slot>
<x-slot name="description">Manage all the invitations which are yet to be accepted.</x-slot>
<x-slot name="content">
<div class="p-8 space-y-4">
<ul class="flex flex-col divide divide-y w-full bg-white rounded-lg shadow">
#forelse($invitations as $key => $invitation)
<li class="flex flex-row">
<div class="flex flex-1 items-center px-8 py-4">
<div class="flex-1 mr-16">
<div class="text-sm dark:text-white">
{{ $invitation->email }}
</div>
</div>
<button wire:click="deleteInvitation" class="text-right flex justify-end">
<x-icon.trash />
</button>
</div>
</li>
#empty
#endforelse
</ul>
<div>
{{ $invitations->links() }}
</div>
</div>
</x-slot>
<x-slot name="footer">
<x-button.secondary wire:click.defer="$set('showInvitationManagementModal', false)">Cancel</x-button.secondary>
</x-slot>
</x-modal.stacked>
</div>
Context
Livewire version: 2.3.5
Laravel version: 8.20.1
Alpine version: 2.8.0
Browser: Chrome
The other answers here both have some minor things to note about them. You don't have to check $invitation, because the typehinting Invitation makes Laravel use Model-Route-Binding, which fetches the corresponding record - or throws a HTTP 404 status code if not found.
Secondly, and this is the actual error you are currently seeing yourself, is that you don't have to do anything to the $this->invitation, since its not set. You should instead pass a parameter to the method.
When looping data in Livewire, it is always recommended to use wire:key, so that Livewire can keep track of each record in the loop.
So for the actual delete method, just call the delete method on the input-variable.
public function deleteInvitation(Invitation $invitation)
{
$invitation->delete();
// Emit an event to notify the user that the record was deleted
// Refresh the parent component to remove the invitation from the list
}
For your blade, add wire:key to the first element in the loop and pass the ID to the method.
(so wire:click="deleteInvitation({{ $invitation->id }})" instead of wire:click="deleteInvitation").
#forelse($invitations as $key => $invitation)
<li class="flex flex-row" wire:key="invitation_{{ $invitation->id }}">
<div class="flex flex-1 items-center px-8 py-4">
<div class="flex-1 mr-16">
<div class="text-sm dark:text-white">
{{ $invitation->email }}
</div>
</div>
<button wire:click="deleteInvitation({{ $invitation->id }})" class="text-right flex justify-end">
<x-icon.trash />
</button>
</div>
</li>
#empty
#endforelse
This in turn means that, since its never used, you can remove the declaration of the $invitation property of that class, the line just after public $showInvitationManagementModal = false;.
public Invitation $invitation;
Try this:
public function deleteInvitation(Invitation $invitation)
{
$this->invitation = $invitation;
$this->invitation->delete();
}