Chunking Results In Laravel Blade Failing Due To Callback - php

I am trying to chunk the results of a laravel collection in my blade template to have 3 columns of records expanding to as many rows as needed. What I have is...
#foreach(Auth::user()->apps()->chunk(3) as $chunk)
<div class="row row-grid gx-0">
#foreach($chunk as $app)
<a href="{{ $app->url }}" class="dropdown-item text-decoration-none p-3 bg-none">
<div class="position-relative">
<i class="fa-solid fa-circle-fill position-absolute text-theme top-0 mt-n2 me-n2 fs-6px d-block text-center w-100"></i>
<i class="fa-solid fa-{{ $app->icon }} h2 opacity-5 d-block my-1"></i>
</div>
<div class="fw-500 fs-10px text-white">{{ ucfirst($app->alias) }}</div>
</a>
#endforeach
</div>
#endforeach
But I am getting the error Too few arguments to function Illuminate\Database\Eloquent\Relations\BelongsToMany::chunk(), 1 passed in /app/storage/framework/views/7d3f05473ba9eb01ea58150355cc97e13e862587.php on line 1 and exactly 2 expected. Taking a look at the Laravel source in Github it appears as a callback function is required which handles the looping for each chunk but this only really works if done from within PHP itself, within a blade template I cant figure out how to to a chunk with a callback. All the information I have been able to find online for Laravel blade chunking shows that this should be working.
My controller method is...
$userApps = Auth::user()->apps();
$chunk = ceil($userApps->count() / 3);
return view('apps', ['apps' => $userApps, 'appsChunk' => $chunk]);

Related

Laravel 8 - reusable code block, change variable depending on a page for charts?

I want to display multiple charts in a single page or different pages. How can I reuse the blade file instead of repeating/retyping the code?
I created a plain blade file _chart-widget.blade.php and I want the variable value to change depending on the page, or depending on what I want to set the variable in each <section> of a page
<!--begin::Charts Widget 1-->
<div class="card {{ $class ?? '' }}">
<!--begin::Header-->
<div class="card-header border-0 pt-5">
<!--begin::Title-->
<h3 class="card-title align-items-start flex-column">
<span class="card-label fw-bolder fs-3 mb-1">Recent Statistics</span>
<span class="text-muted fw-bold fs-7">More than 400 new members</span>
</h3>
<!--end::Title-->
<!--begin::Toolbar-->
<div class="card-toolbar">
<!--begin::Menu-->
<button type="button" class="btn btn-sm btn-icon btn-color-primary btn-active-light-primary" data-kt-menu-trigger="click" data-kt-menu-placement="bottom-end">
{!! theme()->getSvgIcon("icons/duotune/general/gen024.svg", "svg-icon-2") !!}
</button>
{{ theme()->getView('partials/menus/_menu-1') }}
<!--end::Menu-->
</div>
<!--end::Toolbar-->
</div>
<!--end::Header-->
<!--begin::Body-->
<div class="card-body">
<!--begin::Chart-->
<div id="kt_charts_widget_1_chart" style="height: 350px"></div>
<!--end::Chart-->
</div>
<!--end::Body-->
</div>
<!--end::Charts Widget 1-->
How can I make the code above dynamic and reusable when I #include it?
You can include views in Laravel blade template.
here you can read more.
Just use like this:
<div>
#include('_chart-widget')
</div>
If you need to pass data to your widget component, just give parameters as an array to your component:
#include('view.name', ['status' => 'complete'])
If you want variables to be different in each page simply pass vairables from Controller.If you are on the same page and including same blade multiple times this can help you:
#include('view.name', ['code' => 'complete'])
This will set different values for $code variable in different sections.
Check out documentation here.

Lots of duplicate results when looping with condition

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

How to only show all articles that contains a particular value?

Currently using Laravel 8, I have to show on a page all articles but only the ones that contain a specific row value in my Database. For instance, in this one, I have a column in the desired table that is called "is_reserved" as TinyInt acting as a True or false (1-0).
I have searched absolutely everywhere and I cannot understand nor find the right syntax for filtering and show only articles that aren't reserved (is_reserved = 0).
In my blade view file, I have a #foreach loop that fetches my item from my controller, like the following below. Which works by the way, just not the way I intend it to be. I'm out of ideas.
TL:DR: I just want to be able to show all items from my database but only the ones with a specific row value.
<section class="row justify-content-evenly mt-5 mx-sm-3">
#foreach ($donations as $donation)
<article class="box col-md-5 col-sm-12 row p-3 mt-md-3 mt-sm-5 d-flex justify-content-around">
<img src="{{ $donation->image }}" alt="image" class="col" style="border-radius: 100%;">
<div class="col">
<p style="text-align: justify;">{{ Str::limit($donation->description, 80) }}</p>
<div class="d-flex justify-content-start flex-column text-left" style="width: auto; height: 100px;">
<h5>Location: Quebec</h5>
<p>Meteo: Cold</p>
<div class="row justify-content-between">
<button class="col-5 btn yellowBtn">reserve</button>
<a class="col-5 btn greenBtn" href="{{route('view-item', $donation->id)}}">View</a>
</div>
</div>
</div>
</article>
#endforeach
Move the logic to the controller / service before looping through them, then send the necessary rows to your blade (probably with a $is_reserved boolean in the array/object)
Keep in mind that if you're diving into logic in the blade / template file itself, it's best to move it back a step and just provide the template the simplest data you can.
Taking your question as an example, before sending the rows to the template, and just show the ones that match your need.
e.g.
$rows = DB::table('your_table')->where('is_reserved', '1')->get();
return $rows; //or extend your template here
Otherwise, you can ad an #if condition right to your template, and render only if ceratin condition is met

Getting error "Typed property must not be accessed before initialization" - Laravel Livewire

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();
}

Included blade template repeating in each foreach loop iteration

I'm using Blade templating with Laravel and I'm trying to use a #foreach loop to display notifications. The problem is that if I have say 10 notifications, the first notification is repeated 10 times.
The code to output each notification:
#foreach ( Auth::user()->unreadNotifications as $notification )
{{ $notification->type->web_template }}
{{ $notification->id }}
#include($notification->type->web_template)
#endforeach
web_template will output a path to the template: notifications.web.user_alert
For each iteration of the loop the {{ $notification->type->web_template }} and {{ $notification->id }} will output what they're supposed to but #include($notification->type->web_template) will only output the first notification each time.
So the output will look like:
156 notification.web.new_message
You have a new message from Joe.
154 notification.web.user_alert
You have a new message from Joe.
145 notification.web.new_like
You have a new message from Joe.
I think it's some sort of cache issue maybe, but I couldn't find anyone with the same problem.
Any ideas?
UPDATE: Adding some code
Example notification view:
#extends('layouts.notification-wrapper')
#section('url', url('jobs/'.$notification->job_id.'#highlight'.$notification->bid_id))
#section('image', '/assets/img/no-photo.jpg')
#section('header', $notification->collector->firstname . ' ' . $notification->collector->secondname)
#section('description')
has placed a bid of €{{ number_format($notification->bid()->withTrashed()->first()->amount,0) }} on your job.
#stop
Notification wrapper:
<li #if(!$notification->read)
class="unread"
#endif>
<a href="#yield('url')" data-id="{{ $notification->id }}">
<div class="pull-left">
<img src="#yield('image')" class="img-circle" alt="user image">
</div>
<h4>
#yield('header')
<small><i class="fa fa-clock-o"></i> {{ $notification->created_at->diffForHumans()}}</small>
</h4>
<p> #yield('description')</p>
</a>
</li>
Answering my own question!
Found this: Laravel Blade Templates Section Repeated / cache error
Basically whatever way it works I need to overwrite my sections when looping and using #yield... I think. So I need to replace #stop with #overwrite in my views.

Categories