Adgower

Member Since 10 Months Ago

Oklahoma City

Experience Points
34,640
Total
Experience

360 experience to go until the next level!

In case you were wondering, you earn Laracasts experience when you:

  • Complete a lesson — 100pts
  • Create a forum thread — 50pts
  • Reply to a thread — 10pts
  • Leave a reply that is liked — 50pts
  • Receive a "Best Reply" award — 500pts
Lessons Completed
318
Lessons
Completed
Best Reply Awards
0
Best Reply
Awards
  • start your engines Created with Sketch.

    Start Your Engines

    Earned once you have completed your first Laracasts lesson.

  • first-thousand Created with Sketch.

    First Thousand

    Earned once you have earned your first 1000 experience points.

  • 1-year Created with Sketch.

    One Year Member

    Earned when you have been with Laracasts for 1 year.

  • 2-years Created with Sketch.

    Two Year Member

    Earned when you have been with Laracasts for 2 years.

  • 3-years Created with Sketch.

    Three Year Member

    Earned when you have been with Laracasts for 3 years.

  • 4-years Created with Sketch.

    Four Year Member

    Earned when you have been with Laracasts for 4 years.

  • 5-years Created with Sketch.

    Five Year Member

    Earned when you have been with Laracasts for 5 years.

  • school-in-session Created with Sketch.

    School In Session

    Earned when at least one Laracasts series has been fully completed.

  • welcome-newcomer Created with Sketch.

    Welcome To The Community

    Earned after your first post on the Laracasts forum.

  • full-time-student Created with Sketch.

    Full Time Learner

    Earned once 100 Laracasts lessons have been completed.

  • pay-it-forward Created with Sketch.

    Pay It Forward

    Earned once you receive your first "Best Reply" award on the Laracasts forum.

  • subscriber Created with Sketch.

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • lifer Created with Sketch.

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • evangelist Created with Sketch.

    Laracasts Evangelist

    Earned if you share a link to Laracasts on social media. Please email [email protected] with your username and post URL to be awarded this badge.

  • chatty-cathy Created with Sketch.

    Chatty Cathy

    Earned once you have achieved 500 forum replies.

  • lara-veteran Created with Sketch.

    Laracasts Veteran

    Earned once your experience points passes 100,000.

  • 10k-strong Created with Sketch.

    Ten Thousand Strong

    Earned once your experience points hits 10,000.

  • lara-master Created with Sketch.

    Laracasts Master

    Earned once 1000 Laracasts lessons have been completed.

  • laracasts-tutor Created with Sketch.

    Laracasts Tutor

    Earned once your "Best Reply" award count is 100 or more.

  • laracasts-sensei Created with Sketch.

    Laracasts Sensei

    Earned once your experience points passes 1 million.

  • top-50 Created with Sketch.

    Top 50

    Earned once your experience points ranks in the top 50 of all Laracasts users.

  • Community Pillar

    Earned once your experience points ranks in the top 10 of all Laracasts users.

Level 7
34,640 XP
Apr
30
1 week ago
Activity icon

Commented on Blade Components And CSS Grids

This generates another query

Mar
27
1 month ago
Activity icon

Commented on Assets, Layouts And Fancy Selects

I think the reason he used "Larry Laracore" was because the icons have a robot/computer theme, and therefore the core represents a cpu core? I thought it was clever.

Mar
05
2 months ago
Activity icon

Commented on Finding The Documentation Page

7:39 popo = police not plain old php lol.

Feb
11
2 months ago
Activity icon

Started a new Conversation Infinity Scroll Stops Working

Hey for some reason my infinite scroll stops working when I Enter a search term and then clear out the input, but if I put 2 spaces and clear out the input it works fine again.

index.blade.php

@extends('layouts.app')

@section('styles')

@endsection

@section('scripts')
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.6.0/gsap.min.js"></script>
<script>
    let animations = [];

    Livewire.hook('message.received', () => {
        let users = Array.from(document.querySelectorAll('[animate-move]'));

        animations = users.map(user => {
            let oldTop = user.getBoundingClientRect().top;
            let oldLeft = user.getBoundingClientRect().left;

            return () => {
                let newTop = user.getBoundingClientRect().top;
                let newLeft = user.getBoundingClientRect().left;

                gsap.fromTo(user, {x:(oldLeft - newLeft), y:(oldTop - newTop)}, {duration: 1, x:0, y:0})
            }
        }) ;
    });

    Livewire.hook('message.processed', () => {
        while(animations.length) {
            animations.shift()();
        }
    });
</script>
@endsection

@section('content')
<livewire:users.list-users />
@endsection

ListUsers.php

<?php

namespace App\Http\Livewire\Users;

use App\Models\User;
use Livewire\Component;

class ListUsers extends Component
{
    public $totalRecords;
    public $loadAmount = 8;
    public $users;
    public $input;
    public $totalFilteredRecords;

    public function mount()
    {
        $this->totalRecords = User::count();
    }

    public function render()
    {

        $this->users = User::orderBy('created_at', 'desc')
        ->limit($this->loadAmount)
        ->when($this->input != '', function($query) {
            return $query->where('name', 'like', '%'.$this->input.'%');
        })
        ->get();

        $this->totalFilteredRecords = $this->users->count();

        return view('livewire.users.list-users');
    }

    public function loadMore()
    {
        $this->loadAmount += 8;
    }

    public function deleteUser(User $user)
    {
        $this->users = $this->users->whereNotIn('id', $user->id);

        $user->delete();

        $this->totalRecords = User::count();
    }
}

list-users.blade.php

<div class="row mt-5">
    <div class="col-12 mb-4">
        <div class="row justify-content-between">
            <div class="col-auto">
                <input wire:model='input' class="form-control form-control-lg" type="search"
                    placeholder="Search By Name" autofocus>
            </div>
            <div class="col-auto">{{ $totalFilteredRecords }}/{{ $totalRecords }} Users</div>
        </div>
    </div>
    @foreach ($users as $user)
    <div wire:key='{{ $user->id }}' animate-move @if ($loop->last) id="last_record" @endif class="col-3 mb-4">
        <div class="card">
            <div class="card-body">
                <h5 class="card-title">{{ $user->name }}</h5>
                <h6 class="card-subtitle mb-2 text-muted">{{ $user->created_at }}</h6>
                <a href="#" class="card-link">{{ $user->email }}</a>
                <button wire:click='deleteUser({{ $user->id }})' class="btn btn-outline-danger">Delete</button>
            </div>
        </div>
    </div>
    @endforeach

    <script>
        const lastRecord = document.getElementById('last_record');

        const options= {
            root: null,
            threshold: 1,
            rootMargin: '0px'
        }

        const observer = new IntersectionObserver((entries, observer) => {
            entries.forEach(entry => {
                if(entry.isIntersecting) {
                    @this.loadMore()
                }
            });
        });

        observer.observe(lastRecord);
    </script>
</div>

Any Tips would be greatly appreciated!

Feb
04
3 months ago
Activity icon

Awarded Best Reply on Optimize Query

Hey I went this route using package has many deep thanks

use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
    public function eventStudents()
    {
        return $this->hasManyDeepFromRelations($this->events(), (new Event)->students());
    }

In my query I use

withCount(‘eventStudents’)

I can also easily sort by the count

Activity icon

Replied to Optimize Query

Hey I went this route using package has many deep thanks

use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
    public function eventStudents()
    {
        return $this->hasManyDeepFromRelations($this->events(), (new Event)->students());
    }

In my query I use

withCount(‘eventStudents’)

I can also easily sort by the count

Feb
03
3 months ago
Activity icon

Started a new Conversation Optimize Query

I have The following:

Users/Students
Events
Courses

I want to retrieve the students count for each course.

Course model has a relationship with events (polymorphic)

public function events()
    {
        return $this->morphToMany('App\Models\Event', 'schedulable');
    }

Event model has relationship with students/users

public function students()
    {
        return $this->belongsToMany('App\Models\User');
    }

I can get the information I want using the following method on the course model

public function getStudentsCount()
    {
        $count = 0;

        foreach($this->events as $event) {
            $count += intval($event->students->count());
        }

        return $count;
    }

I can access the data using

$course->getStudentsCount() // returns -> 5017

How can I make this more efficient when I'm listing out the courses and want to order by "popular"

Any tips would be greatly appreciated.

Thanks

Dec
15
4 months ago
Activity icon

Awarded Best Reply on Livewire FilePond Clear After Upload

It's working now: I think it was a caching issue?

<div>
    <button wire:click="upload" class="btn btn-primary">Upload</button>
    {{-- <input wire:model="newDocument" type="file"> --}}
    @error('newDocument')
    {{ $message }}
    @enderror
    <div wire:ignore x-data x-init="

        FilePond.setOptions({
            server: {
                process: (fieldName, file, metadata, load, error, progress, abort, transfer, options) => {
                    @this.upload('newDocument', file, load, error, progress)
                },
                revert: (filename, load) => {
                    @this.removeUpload('newDocument', filename, load)
                },
            },
        });
        var Pond = FilePond.create($refs.input);
        this.addEventListener('pondReset', e => {
            Pond.removeFiles();
        });


    ">

        <input wire:model="newDocument" type="file" x-ref="input">
    </div>

    <ul class="list-group">
        @foreach ($event->documents as $document)
        <li class="list-group-item d-flex justify-content-between align-items-center">
            <a wire:click.prevent="$emitTo('admin.courses.show-document', 'selectedDocument', '{{ $document->id }}')"
                href="#" target="_blank"><i class='far fa-file-pdf'></i>{{ $document->name }}</a>

            {{-- <span class="badge bg-primary rounded-pill">14</span> --}}
        </li>
        @endforeach
    </ul>
</div>

Activity icon

Replied to Livewire FilePond Clear After Upload

It's working now: I think it was a caching issue?

<div>
    <button wire:click="upload" class="btn btn-primary">Upload</button>
    {{-- <input wire:model="newDocument" type="file"> --}}
    @error('newDocument')
    {{ $message }}
    @enderror
    <div wire:ignore x-data x-init="

        FilePond.setOptions({
            server: {
                process: (fieldName, file, metadata, load, error, progress, abort, transfer, options) => {
                    @this.upload('newDocument', file, load, error, progress)
                },
                revert: (filename, load) => {
                    @this.removeUpload('newDocument', filename, load)
                },
            },
        });
        var Pond = FilePond.create($refs.input);
        this.addEventListener('pondReset', e => {
            Pond.removeFiles();
        });


    ">

        <input wire:model="newDocument" type="file" x-ref="input">
    </div>

    <ul class="list-group">
        @foreach ($event->documents as $document)
        <li class="list-group-item d-flex justify-content-between align-items-center">
            <a wire:click.prevent="$emitTo('admin.courses.show-document', 'selectedDocument', '{{ $document->id }}')"
                href="#" target="_blank"><i class='far fa-file-pdf'></i>{{ $document->name }}</a>

            {{-- <span class="badge bg-primary rounded-pill">14</span> --}}
        </li>
        @endforeach
    </ul>
</div>

Activity icon

Started a new Conversation Livewire FilePond Clear After Upload

I have the following which uploads a file fine:

<div>
    <button wire:click="upload" class="btn btn-primary">Upload</button>
    <input wire:model="newDocument" type="file">
    @error('newDocument')
    {{ $message }}
    @enderror
    <div wire:ignore x-data x-init="

        FilePond.setOptions({
            server: {
                process: (fieldName, file, metadata, load, error, progress, abort, transfer, options) => {
                    @this.upload('newDocument', file, load, error, progress)
                },
                revert: (filename, load) => {
                    @this.removeUpload('newDocument', filename, load)
                },
            },
        });
this.addEventListener('pondReset', e => {
            FilePond.removeFile();
        });

    ">

        <input wire:model="newDocument" type="file" class="filepond">
    </div>

    <ul class="list-group">
        @foreach ($event->documents as $document)
        <li class="list-group-item d-flex justify-content-between align-items-center">
            <a wire:click.prevent="$emitTo('admin.courses.show-document', 'selectedDocument', '{{ $document->id }}')"
                href="#" target="_blank"><i class='far fa-file-pdf'></i>{{ $document->name }}</a>

            {{-- <span class="badge bg-primary rounded-pill">14</span> --}}
        </li>
        @endforeach
    </ul>
</div>

but it doesn't clear the input after upload. I assume it is because wire:ignore?

in my upload method I set $this->newDocument = NULL. I assume I need to somehow use alpine/js to do the same concept? Is this the right direction?

Thanks

UPDATE:

I found this link: https://forum.laravel-livewire.com/t/how-to-reset-filepond-input-file/1595

But when I run

FilePond.removeFile();

It says FilePond.removeFile is not a function...

https://pqina.nl/filepond/docs/patterns/api/filepond-instance/#removing-files

any tips?

UPDATE:

I found this https://forum.laravel-livewire.com/t/clear-out-filepone-files/2449/2

He says I need to set it equal to an instance of FilePond

when I do that I get same problem:

var pond = FilePond.create($refs.input);

still says .removeFiles is not a function

Activity icon

Replied to File URL

I change to what you said and I deleted the sym link and re ran php artisan storage:link on the vm in the root directory of the project and now it is working. Thank you.

Dec
14
4 months ago
Activity icon

Started a new Conversation File URL

I am able to successfully upload a file to:

storage/app/public/documents/events/FILENAME.pdf

when I try to access it doesn't show in browser:

public function getUrl()
    {
        return Storage::disk('Event')->url($this->file_name);
    }

filesystems.php:

'Event' => [
            'driver' => 'local',
            'root' => storage_path('app/public/documents/events'),
            'url' => env('APP_URL').'/documents/events',
            'visibility' => 'public',
        ],

'links' => [
        public_path('storage') => storage_path('app/public'),
    ],

url generated:

https://laravel.local/documents/events/FILENAME.pdf

I ran storage:link and I see the file being uploaded, but the url its generating is wrong when I try to create a url for the file.

I'm using Homestead on windows 10, and I think I may have not done it right?

Any tips?

Thanks

Dec
09
4 months ago
Activity icon

Started a new Conversation WithCount Morph Through?

I have the following setup: Products has many items/variations, items has many inventories, and an inventory belongs to a morph (stockable which is a warehouse or a store), and the stockable (warehouse or store) belongs to 1 a region.

Maybe I am making this complicated, but I am trying to see how many regions a product is in and return for example: "Coding Product 1 is in 5 regions", so it returns the count of regions for each product.

I have setup a has Many through (Inventory::class, Item::class) on the Product to get the inventories for example $product->inventories. This is the part where I am stuck. If I $product->inventories->first()->stockable->region->id, gives me the region->id. This seems inefficient, and I was hoping I could deploy a has one through, but the inventory contains the stockable morphto relationship...

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    use HasFactory;

    public function items()
    {
        return $this->hasMany(Item::class);
    }

    public function inventories()
    {
        return $this->hasManyThrough(Inventory::class, Item::class);
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Item extends Model
{
    use HasFactory;

    public function inventories()
    {
        return $this->hasMany(Inventory::class);
    }

    public function product()
    {
        return $this->belongsTo(Product::class);
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Lukeraymonddowning\Mula\Facades\Mula;

class Inventory extends Model
{
    use HasFactory;

    public function stockable()
    {
        return $this->morphTo();
    }

    public function item()
    {
        return $this->belongsTo(Item::class);
    }

    public function getValueAttribute()
    {
        return $this->quantity * $this->item->price;
    }

    public function getFormattedValueAttribute()
    {
        return Mula::parse($this->value, 'USD')->display();
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Lukeraymonddowning\Mula\Facades\Mula;

class Store extends Model
{
    use HasFactory;

    public function region()
    {
        return $this->belongsTo(Region::class);
    }

    public function itemInventory()
    {
        return $this->morphMany(Inventory::class, 'stockable');
    }

    public function getInventoryValueAttribute()
    {
        $total = 0;

        foreach($this->itemInventory as $inventory) {
            $total += $inventory->value;
        }

        return $total;
    }

    public function getFormattedInventoryValueAttribute()
    {
        return Mula::parse($this->inventory_value, 'USD')->display();
    }
}

Here is the query i'm currently building:

$products = Product::when($this->searchProducts != '', function($query) {
            $query->where('title', 'like', '%'.$this->searchProducts.'%');
        })->withCount(['items', 'inventories as store_count' => function($query) {
            $query->where('stockable_type', 'App\Models\Store');
        }, 'inventories as warehouse_count' => function($query) {
            $query->where('stockable_type', 'App\Models\Warehouse');
        }])->withAvg('items', 'price')->withAvg(['inventories as store_avg_quantity' => function($query) {
            $query->where('stockable_type', 'App\Models\Store');
        }, 'inventories as warehouse_avg_quantity' => function($query) {
            $query->where('stockable_type', 'App\Models\Warehouse');
        }], 'quantity')->withSum(['inventories as store_quantity' => function($query) {
            $query->where('stockable_type', 'App\Models\Store');
        }, 'inventories as warehouse_quantity' => function($query) {
            $query->where('stockable_type', 'App\Models\Warehouse');
        }, 'inventories as total_quantity'], 'quantity')->when($this->sortQuantity == true, function($query) {
            $query->orderBy('total_quantity', $this->sortDirection ? 'asc' : 'desc' );
        })->get();

I want to add withCount and get regions_count

any tips?

Activity icon

Replied to How To Simplify This Validation?

thanks ill check it out.

Dec
08
5 months ago
Activity icon

Started a new Conversation Slow Queries From Custom Accessors

I have a problem that I have created custom accessors to pull some data I need, but it is really slow and basically generates about 500 more queries than I just just query the model and use with on the relationships. Could someone point me in the right direction? Do I need to convert to sql query instead of using all the methods?

I'm using laravel debugbar to get this information

controller: using with saves about 10 queries

$regions = Region::when($this->searchRegions != '', function($query) {
            $query->where('title', 'like', '%'.$this->searchRegions.'%');
        })->with('stores')->with('warehouse')->get();

view

<div class="row">
        @foreach ($regions->sortByDesc('inventory_value') as $region)
        <div class="col-xs col-md-6 col-lg-4 col-xxl-3 mt-4">
            <div class="card">
                <div class="card-body">
                    <h5 class="card-title">{{ $region->title }}</h5>
                    <p class="card-text">
                        <a href="#">
                            {{ $region->warehouse->title }}
                        </a>
                    </p>
                    <p class="card-text">Stores: {{ count($region->stores) }}</p>
                    <p class="card-text">Unique Inventory Items: {{ count($region->itemInventory) }}</p>
                    <p class="card-text">Region Inventory Value: {{ $region->formatted_inventory_value }}</p>
                    <a href="#" class="btn btn-primary">View</a>
                </div>
            </div>
        </div>
        @endforeach
    </div>

model:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Lukeraymonddowning\Mula\Facades\Mula;

class Region extends Model
{
    use HasFactory;

    public function stores()
    {
        return $this->hasMany(Store::class);
    }

    public function warehouse()
    {
        return $this->belongsTo(Warehouse::class);
    }

    public function getInventoryValueAttribute()
    {
        $total = 0;

        foreach($this->stores as $store) {
            $total += $store->inventory_value;
        }

        $total += $this->warehouse->inventory_value;

        return $total;
    }

    public function getFormattedInventoryValueAttribute()
    {
        return Mula::parse($this->inventory_value, 'USD')->display();
    }

    public function getItemInventoryAttribute()
    {
        $itemIds = collect();

        foreach($this->stores as $store) {
            $itemIds = $itemIds->merge($store->itemInventory->pluck('item_id'));
        }

        $itemIds = $itemIds->merge($this->warehouse->itemInventory->pluck('item_id'));

        $items = Item::find($itemIds->unique());

        return $items;
    }
}

Basically I'm dipping into multiple accessors a few models deep, and piling up the queries. Any tips would be great! Thanks.

Activity icon

Started a new Conversation How To Simplify This Validation?

This accomplishes what I need, but if someone could point me in the right direction with a way to simplify that would be great!

// https://laravel.com/docs/8.x/validation#conditionally-adding-rules
    $request->validate([
        'first_name'     => 'required',
        'last_name'      => 'required',
        'email'          => 'required_without_all:id_number,dob',
        'id_number'     => 'required_without_all:email,dob',
        'dob'            => 'required_without_all:email,id_number',
        'hours_per_week' => 'nullable|numeric',
        'hours_per_day'  => 'nullable|numeric',
        'supervisor'     => 'nullable|string',
        'start_date'     => 'date_format:Y-m-d'
    ]);

    if ($request->email != null && $request->id_number != null) {
        $request->validate([
            'email'      => 'email',
            'id_number' => 'digits:4'
        ]);
    }

    if ($request->email != null && $request->dob != null) {
        $request->validate([
            'email' => 'email',
            'dob'   => 'date_format:Y-m-d'
        ]);
    }

    if ($request->id_number != null && $request->dob != null) {
        $request->validate([
            'id_number' => 'digits:4',
            'dob'        => 'date_format:Y-m-d'
        ]);
    }

    if ($request->email != null) {
        $request->validate([
            'email' => 'email'
        ]);
    }

    if ($request->id_number != null) {
        $request->validate([
            'id_number' => 'digits:4'
        ]);
    }

    if ($request->dob != null) {
        $request->validate([
            'dob' => 'date_format:Y-m-d'
        ]);
    }
Dec
03
5 months ago
Activity icon

Awarded Best Reply on Nested Livewire Component Requires Double Click

I think the problem is this from the livewire docs:

Nested components CAN accept data parameters from their parents, HOWEVER they are not reactive like props from a Vue component.

So I moved my buttons up to the main component instead of the nested component. todos-list.blade.php:

<div class="row flex-column">
    @foreach ($todos as $todo)
    <div class="border shadow-sm rounded mx-3 mb-2 px-3 py-2 d-flex justify-content-between align-items-center">
        <livewire:todos.todo-show :todo="$todo" :key="$todo->id"/>
            <div>
                @if ($todo->completed)
                <button class="btn btn-outline-success" wire:click="toggleTodo({{ $todo->id }})">Completed!</button>
                @else
                <button class="btn btn-primary" wire:click="toggleTodo({{ $todo->id }})">Complete</button>
                @endif
                <button class="btn btn-outline-danger" wire:click="removeTodo({{ $todo->id }})">Delete</button>
            </div>
        </div>
        @endforeach

</div>

and then moved the methods from TodoShow -> TodosList

Solved it...

Another way to solve it: I added a property to store the value and used the mount function like this: TodoShow:

<?php

namespace App\Http\Livewire\Todos;

use App\Models\Todo;
use Livewire\Component;

class TodoShow extends Component
{
    public $todo;
    public $status;

    public function mount()
    {
        $this->status = $this->todo->completed;
    }

    public function render()
    {
        return view('livewire.todos.todo-show');
    }

    public function removeTodo(Todo $todo)
    {
        $todo->delete();

        $this->emitTo('todos.todos-list', 'render');
    }

    public function toggleTodo(Todo $todo)
    {
        $todo->toggle();

        $this->status = $todo->completed;

        $this->emitTo('todos.todos-list', 'render');
    }
}

Then in the view todo-show.blade.php I swapped the if statement to if($status)

Activity icon

Replied to Nested Livewire Component Requires Double Click

I think the problem is this from the livewire docs:

Nested components CAN accept data parameters from their parents, HOWEVER they are not reactive like props from a Vue component.

So I moved my buttons up to the main component instead of the nested component. todos-list.blade.php:

<div class="row flex-column">
    @foreach ($todos as $todo)
    <div class="border shadow-sm rounded mx-3 mb-2 px-3 py-2 d-flex justify-content-between align-items-center">
        <livewire:todos.todo-show :todo="$todo" :key="$todo->id"/>
            <div>
                @if ($todo->completed)
                <button class="btn btn-outline-success" wire:click="toggleTodo({{ $todo->id }})">Completed!</button>
                @else
                <button class="btn btn-primary" wire:click="toggleTodo({{ $todo->id }})">Complete</button>
                @endif
                <button class="btn btn-outline-danger" wire:click="removeTodo({{ $todo->id }})">Delete</button>
            </div>
        </div>
        @endforeach

</div>

and then moved the methods from TodoShow -> TodosList

Solved it...

Another way to solve it: I added a property to store the value and used the mount function like this: TodoShow:

<?php

namespace App\Http\Livewire\Todos;

use App\Models\Todo;
use Livewire\Component;

class TodoShow extends Component
{
    public $todo;
    public $status;

    public function mount()
    {
        $this->status = $this->todo->completed;
    }

    public function render()
    {
        return view('livewire.todos.todo-show');
    }

    public function removeTodo(Todo $todo)
    {
        $todo->delete();

        $this->emitTo('todos.todos-list', 'render');
    }

    public function toggleTodo(Todo $todo)
    {
        $todo->toggle();

        $this->status = $todo->completed;

        $this->emitTo('todos.todos-list', 'render');
    }
}

Then in the view todo-show.blade.php I swapped the if statement to if($status)

Activity icon

Replied to Nested Livewire Component Requires Double Click

If I don't use a nested component it works fine. For example todo-list has the foreach and buttons etc.

If I use the nested component like I am now that is where the problem is.

Activity icon

Replied to Nested Livewire Component Requires Double Click

database only shows 0 and 1 as value when changed. So it stays 0 and 1.

Activity icon

Replied to Nested Livewire Component Requires Double Click

I just noticed when I first click the button it does change the value in the database correctly, but it isn't until 2nd click that the button re-renders and shows the button correctly and updates the value in db. The 3rd click it correctly toggles value in database and button view correctly.

Activity icon

Replied to Nested Livewire Component Requires Double Click

the default value is 0/false in database

Here is the test of that method:

[email protected]:~/code/todo-livewire$ php artisan tinker
Psy Shell v0.10.4 (PHP 7.4.11 — cli) by Justin Hileman
>>> $todo = Todo::find(1);
[!] Aliasing 'Todo' to 'App\Models\Todo' for this Tinker session.
=> App\Models\Todo {#4225
     id: 1,
     title: "I was a large pool.",
     completed: 1,
     created_at: "2020-12-03 22:34:15",
     updated_at: "2020-12-03 22:36:38",
   }
>>> $todo->toggle();
=> null
>>> dump($todo);
App\Models\Todo^ {#4225
  #fillable: array:2 [
    0 => "title"
    1 => "completed"
  ]
  #connection: "mysql"
  #table: "todos"
  #primaryKey: "id"
  #keyType: "int"
  +incrementing: true
  #with: []
  #withCount: []
  #perPage: 15
  +exists: true
  +wasRecentlyCreated: false
  #attributes: array:5 [
    "id" => 1
    "title" => "I was a large pool."
    "completed" => false
    "created_at" => "2020-12-03 22:34:15"
    "updated_at" => "2020-12-03 22:37:17"
  ]
  #original: array:5 [
    "id" => 1
    "title" => "I was a large pool."
    "completed" => false
    "created_at" => "2020-12-03 22:34:15"
    "updated_at" => "2020-12-03 22:37:17"
  ]
  #changes: array:2 [
    "completed" => false
    "updated_at" => "2020-12-03 22:37:17"
  ]
  #casts: []
  #classCastCache: []
  #dates: []
  #dateFormat: null
  #appends: []
  #dispatchesEvents: []
  #observables: []
  #relations: []
  #touches: []
  +timestamps: true
  #hidden: []
  #visible: []
  #guarded: array:1 [
    0 => "*"
  ]
}
=> App\Models\Todo {#4225
     id: 1,
     title: "I was a large pool.",
     completed: false,
     created_at: "2020-12-03 22:34:15",
     updated_at: "2020-12-03 22:37:17",
   }
>>> $todo->toggle();
=> null
>>> dump($todo);
App\Models\Todo^ {#4225
  #fillable: array:2 [
    0 => "title"
    1 => "completed"
  ]
  #connection: "mysql"
  #table: "todos"
  #primaryKey: "id"
  #keyType: "int"
  +incrementing: true
  #with: []
  #withCount: []
  #perPage: 15
  +exists: true
  +wasRecentlyCreated: false
  #attributes: array:5 [
    "id" => 1
    "title" => "I was a large pool."
    "completed" => true
    "created_at" => "2020-12-03 22:34:15"
    "updated_at" => "2020-12-03 22:37:35"
  ]
  #original: array:5 [
    "id" => 1
    "title" => "I was a large pool."
    "completed" => true
    "created_at" => "2020-12-03 22:34:15"
    "updated_at" => "2020-12-03 22:37:35"
  ]
  #changes: array:2 [
    "completed" => true
    "updated_at" => "2020-12-03 22:37:35"
  ]
  #casts: []
  #classCastCache: []
  #dates: []
  #dateFormat: null
  #appends: []
  #dispatchesEvents: []
  #observables: []
  #relations: []
  #touches: []
  +timestamps: true
  #hidden: []
  #visible: []
  #guarded: array:1 [
    0 => "*"
  ]
}
=> App\Models\Todo {#4225
     id: 1,
     title: "I was a large pool.",
     completed: true,
     created_at: "2020-12-03 22:34:15",
     updated_at: "2020-12-03 22:37:35",
   }
>>> $todo->toggle();
=> null
>>> dump($todo);
App\Models\Todo^ {#4225
  #fillable: array:2 [
    0 => "title"
    1 => "completed"
  ]
  #connection: "mysql"
  #table: "todos"
  #primaryKey: "id"
  #keyType: "int"
  +incrementing: true
  #with: []
  #withCount: []
  #perPage: 15
  +exists: true
  +wasRecentlyCreated: false
  #attributes: array:5 [
    "id" => 1
    "title" => "I was a large pool."
    "completed" => false
    "created_at" => "2020-12-03 22:34:15"
    "updated_at" => "2020-12-03 22:37:40"
  ]
  #original: array:5 [
    "id" => 1
    "title" => "I was a large pool."
    "completed" => false
    "created_at" => "2020-12-03 22:34:15"
    "updated_at" => "2020-12-03 22:37:40"
  ]
  #changes: array:2 [
    "completed" => false
    "updated_at" => "2020-12-03 22:37:40"
  ]
  #casts: []
  #classCastCache: []
  #dates: []
  #dateFormat: null
  #appends: []
  #dispatchesEvents: []
  #observables: []
  #relations: []
  #touches: []
  +timestamps: true
  #hidden: []
  #visible: []
  #guarded: array:1 [
    0 => "*"
  ]
}
=> App\Models\Todo {#4225
     id: 1,
     title: "I was a large pool.",
     completed: false,
     created_at: "2020-12-03 22:34:15",
     updated_at: "2020-12-03 22:37:40",
   }
>>>
Activity icon

Started a new Conversation Nested Livewire Component Requires Double Click

I have a simple todo app:

The problem is when I click a button to toggle completed. The button requires you to click it twice. When I inspect I see that on the first click it adds to the element:

wire:initial-data="{"fingerprint":{"id":"3k5l2c0etHn1H0aVPRuT","name":"todos.todo-show","locale":"en"},"effects":{"listeners":[]},"serverMemo":{"children":[],"errors":[],"htmlHash":"528e0713","data":{"todo":[]},"dataMeta":{"models":{"todo":{"class":"App\Models\Todo","id":10,"relations":[],"connection":"mysql"}}},"checksum":"11a5f638221702a54589fabc2716b565ad6c51c08d2e4665cb6009556ad36840"}}"

Then on the second click it works fine and continues to work fine. The delete button works fine on first click.

If you can point me in the right direction that would help thanks!

Livewire components: TodoShow:

<?php

namespace App\Http\Livewire\Todos;

use App\Models\Todo;
use Livewire\Component;

class TodoShow extends Component
{
    public $todo;

    public function render()
    {
        return view('livewire.todos.todo-show');
    }

    public function removeTodo(Todo $todo)
    {
        $todo->delete();

        $this->emitTo('todos.todos-list', 'render');
    }

    public function toggleTodo(Todo $todo)
    {
        $todo->toggle();

        $this->emitTo('todos.todos-list', 'render');
    }
}

TodosList:

<?php

namespace App\Http\Livewire\Todos;

use App\Models\Todo;
use Livewire\Component;

class TodosList extends Component
{
    protected $listeners = ['render'];

    public function render()
    {
        $todos = Todo::latest()->get();

        return view('livewire.todos.todos-list', compact('todos'));
    }
}

Views: todos-list.blade.php

<div class="row flex-column">
    @foreach ($todos as $todo)
        <livewire:todos.todo-show :todo="$todo" :key="$todo->id"/>
    @endforeach
</div>

todo-show.blade.php:

<div class="border shadow-sm rounded mx-3 mb-2 px-3 py-2 d-flex justify-content-between align-items-center">
    <div>
        {{ $todo->title }}
    </div>
    <div>
        @if ($todo->completed)
        <button class="btn btn-outline-success" wire:click="toggleTodo({{ $todo->id }})">Completed!</button>
        @else
        <button class="btn btn-primary" wire:click="toggleTodo({{ $todo->id }})">Complete</button>
        @endif
        <button class="btn btn-outline-danger" wire:click="removeTodo({{ $todo->id }})">Delete</button>
    </div>
</div>

Todo.php model:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Todo extends Model
{
    use HasFactory;

    protected $fillable = ['title', 'completed'];

    public function toggle()
    {
        $this->update([
            'completed' => !$this->completed,
        ]);
    }
}
Activity icon

Awarded Best Reply on Livewire Nested Component Not Working

I solve it by changing the key used on the todo-show model:

:key="$loop->index" -> :key="$todo->id"
Activity icon

Replied to Livewire Nested Component Not Working

I solve it by changing the key used on the todo-show model:

:key="$loop->index" -> :key="$todo->id"
Activity icon

Replied to Opinions Please: DigitalOcean Or Linode?

I use Digital Ocean also. They Have tons of guides on how to accomplish what you need.

Activity icon

Replied to Which Path Should I Take To Learn Laravel?

If you aren't using build tools such as npm etc then I recommend starting with tailwind by itself and learn how to customize the tools and commands. Once you get the hang of that then implement tailwind with laravel to understand webpack.

Customize development environment to work with tailwind or any css framework, and eventually laravel. If you use vscode search for addon laravel pack and learn how to setup those up for specific workspace.

Try to utilize the command line tools such as php artisan to generate models, controllers, etc (php artisan make:controller TodoController -r, generates a controller with all resource routes)

Learn to setup a server for laravel many methods: Ubuntu nginx/apache Homestead/docker concept

Laravel Documentation - I recommend reread every month because you will come across something you didn't understand at first, but now it is more meaning to you. Laracasts.com Povilas Korop - https://www.youtube.com/channel/UCTuplgOBi6tJIlesIboymGA

Stick with popular packages: https://spatie.be/open-source, etc

Activity icon

Started a new Conversation Livewire Nested Component Not Working

Here is GIF of problem: https://gph.is/g/Z5JDJgw

I have a simple todo app components:

todos.todo-show:

<?php

namespace App\Http\Livewire\Todos;

use Livewire\Component;

class TodoShow extends Component
{
    public $todo;

    public function render()
    {
        return view('livewire.todos.todo-show');
    }
}

todos.todos-list:

<?php

namespace App\Http\Livewire\Todos;

use App\Models\Todo;
use Livewire\Component;

class TodosList extends Component
{
    protected $listeners = ['render'];

    public function render()
    {
        $todos = Todo::latest()->get();

        return view('livewire.todos.todos-list', compact('todos'));
    }
}

todos.todo-form:

<?php

namespace App\Http\Livewire\Todos;

use App\Models\Todo;
use Livewire\Component;

class TodoForm extends Component
{
    public $title;

    public function render()
    {
        return view('livewire.todos.todo-form');
    }

    public function addTodo()
    {
        $this->validate([
            'title' => 'required|min:1',
        ]);

        Todo::create(['title' => $this->title]);
        $this->title = '';

        $this->emitTo('todos.todos-list', 'render');
    }
}

When I add a new todo it duplicates the last todo in the list and doesn't display properly until a full page reload. I expect it to just add the new todo at the top of the list

Here is the nest:

@extends('layouts.app')

@section('content')
<div class="container">
    <livewire:todos.todo-form />
    <livewire:todos.todos-list />
</div>
@endsection

livewire.todos-list.blade.php:

<div class="row flex-column">
    @foreach ($todos as $todo)
        <livewire:todos.todo-show :todo="$todo" :key="$loop->index" />
    @endforeach
</div>

I read in the livewire documentation: "Nested components CAN accept data parameters from their parents, HOWEVER they are not reactive like props from a Vue component."

Not sure if that is the issue.

Nov
18
5 months ago
Activity icon

Replied to How I Can Get All Tickets With Count Replies On It For The Current User

Okay can you post your controller code and the view code you are returning from the controller method?

Activity icon

Replied to How I Can Get All Tickets With Count Replies On It For The Current User

Okay now are you trying to render a view displaying the number of replies for each ticket?

Activity icon

Replied to How I Can Get All Tickets With Count Replies On It For The Current User

I did above.

do you have a file App\Models\User.php, App\Models\Ticket.php, and App\Models\Reply.php?

Can you please post those files?

Activity icon

Replied to How I Can Get All Tickets With Count Replies On It For The Current User

So each user has multiple tickets? and each ticket has multiple replies? Also its not clear if you want the replies for only that user or just all the replies by all users. I think your table for replies isn't setup properly. The setup you have describes a many to many relationship with users and tickets rather than replies. Also I don't know what other columns are on the replies table.

If that is the case on your user model you need:

public function tickets()
{
    return $this->hasMany('App\Models\Ticket');
}

In your ticket model:

public function replies()
{
    return $this->belongsTo('App\Models\Replies');
}

Then in your view you could call like this:

$user->tickets // all the users tickets
$user->tickets->first() // the first ticket in that collection
$user->tickets->first()->replies // the replies for that ticket
$user->tickets->first->replies->where('user_id', $user->id) // the users first ticket with only replies from that user

Then to count:

count($user->tickets->first()->replies)
count($user->tickets->first->replies->where('user_id', $user->id))
Activity icon

Started a new Conversation How To Validate At Least One Required And Only The One Entered?

I want to require atleast one using:

'email' => 'required_without_all:id,dob',
'id' => 'required_without_all:email,dob',
'dob' => 'required_without_all:email,id'

This works fine, but if I try and add validation for the fields like:

'required_without_all:id,dob|email',
'required_without_all:email,dob|digits:4'

If I enter email and not id then it still tries and validates ID even if I have at least one entered. I have tried nullable

Any tips?