ignium

Member Since 2 Years Ago

Experience Points
76,970
Total
Experience

3,030 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
704
Lessons
Completed
Best Reply Awards
2
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 16
76,970 XP
Apr
19
2 weeks ago
Activity icon

Commented on Initial Setup And Design

@andiliang Not sure which navigation item you're referring to specifically, but you can add a css rule and include an x-cloak attribute to elements to prevent them from flashing open on page load.

Reference: AlpineJS x-cloak attribute

Apr
17
3 weeks ago
Activity icon

Replied to Uncaught TypeError: Vue.component Is Not A Function

@successdav This worked for me too. Thanks!

Apr
14
3 weeks ago
Activity icon

Commented on Collection Sorting And Caching Refresher

@kevindrew In a previous episode, when Jeffrey added metadata he just copied and pasted the metadata and only changed the title attribute. He left the other attributes the same (including the date attribute at '2021-05-21'.

In this video, he only updated the "My Fourth Post" publish date to a later date (2021-06-21) so it shows as the last published. Later, when he adds the fifth post he again changes the date (2021-07-21).

Since the other three posts have the same date, they are sorted alphabetically (since that's the order they exist in the directory being read from).

Apr
12
3 weeks ago
Activity icon

Commented on Union And Pseudo Types

I don't believe PHP supports traditional overloading. If you tried to run this code you'd get a Fatal Error, something like Fatal Error: Cannot redefine Class::cancel()

Activity icon

Replied to Single Test Fails With BindingResolutionException After Migrating To Laravel 8.x

@neilstee I'm not sure it's a permission issue, because there are six other tests in that class and four of them call that route without a problem. There's also several other routes in the routes/web file and the other 1000+ tests are all passing. I feel okay with throwing my hands up on this one for now. If I figure it out I'll definitely add the solution here (and be sure to tag you).

Thanks again for you willingness to help. I've seen you on the boards quite a bit helping people out, and just wanted you to know it doesn't go unnoticed!

Activity icon

Replied to Single Test Fails With BindingResolutionException After Migrating To Laravel 8.x

Ugh... That didn't work either. This is really baffling. I might just mark this test skipped. I have other tests in the class that check for each of the things this one tests for. This final test was just kind of make sure it all works together test. And I was hoping to understand what was causing the problem.

I appreciate your time and willingness to help!

Activity icon

Replied to Single Test Fails With BindingResolutionException After Migrating To Laravel 8.x

  • Updating to the route you suggested (but also adding a leading slash) ended in the same result
  • running the test from the vendor file also ended in the same result (I'm on Homestead and by default phpunit is an alias for ./vendor/bin/phpunit) But I also ran it directly as you suggested from the terminal
  • Stack trace ends at .../vendor/laravel/framework/src/Illuminate/Container/Container.php:835 which is the Container.build() method
Activity icon

Replied to Single Test Fails With BindingResolutionException After Migrating To Laravel 8.x

Route $namespace property is still set in the RouteServiceProvider, and the other requests to that route work fine in the same test class. That last part is the part that's confusing me.

From RouteServiceProvider
protected $namespace = 'App\Http\Controllers';

Sidenote: the test fails, but navigating to the page works fine

Activity icon

Replied to Single Test Fails With BindingResolutionException After Migrating To Laravel 8.x

@neilstee It's the unedited default route from the initial installation (Laravel 5.4 I think). I also tried with the static class syntax, but it didn't make a difference.

Route::get('/home', '[email protected]')->name('home');
//Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])
//          ->name('home');
Activity icon

Started a new Conversation Single Test Fails With BindingResolutionException After Migrating To Laravel 8.x

I recently upgraded (with Laravel Shift) to Laravel 8.x and after tweaking a few of my tests, my entire test suite passes except for a single test with the following error:

There was 1 error:

  1. Tests\Feature\UserProfileVerificationFeatureTest::an_admin_profile_will_be_verified_once_edited Illuminate\Contracts\Container\BindingResolutionException: Target class [web] does not exist.

[stack trace removed for brevity]

Caused by ReflectionException: Class web does not exist

[stack trace removed for brevity]

Failing Test

    /** @test */
    public function an_admin_profile_will_be_verified_once_edited()
    {
        $admin = $this->signIn(['admin', 'profile_not_verified']);
        // $admin = User::factory()->admin()->profileNotVerified()->create();
        // $this->actingAs($admin);

        $this->assertFalse($admin->profileIsVerified());

        $unverified_text = __('app.Profile Not Verified');

        $this->get(route('home'))    //<=== FAILS HERE
            ->assertOk()
            ->assertSeeText($unverified_text);

        Livewire::test(StaffAdminForm::class, ['staff' => $admin])
            ->call('submit')
            ->assertHasNoErrors()
            ->assertRedirect(route('staff.show', $admin))
            ->assertSessionHas('flash', $this->getSelfUpdateMessage());

        $admin = $admin->refresh();

        $this->assertTrue($admin->profileIsVerified());

        $this->get(route('home'))
            ->assertOk()
            ->assertDontSeeText($unverified_text);
    }

Passing Test (in same test class)


    /** @test */
    public function a_user_updating_their_unverified_profile_will_verify_it()
    {
        $user = $this->signIn('profile_not_verified');

        $this->assertFalse($user->profileIsVerified());

        $unverified_text = __('app.Profile Not Verified');

        $this->get(route('home'))
            ->assertOk()
            ->assertSeeText($unverified_text);

        Livewire::test(StaffForm::class, ['staff' => $user])
            ->call('submit')
            ->assertHasNoErrors()
            ->assertRedirect(route('staff.show', $user))
            ->assertSessionHas('flash', $this->getSelfUpdateMessage());

        $user = $user->refresh();

        $this->assertTrue($user->profileIsVerified());

        $this->get(route('home'))
            ->assertOk()
            ->assertDontSeeText($unverified_text);
    }

Any ideas why this is happening? The only difference is the parameters for the signIn() function, but I also tested passing an array to the passing test and it still passed, also in both cases the User is created successfully and the first $this->assertFalse($user->profileIsVerified() call passes without a problem. It's only when trying to visit the page that the BindingResolutionException is thrown.

Mar
22
1 month ago
Activity icon

Replied to Livewire Assuming Date Inputs Are In UTC

So this wasn't a complete fix, but removing the accessor for the end date property as you mentioned, but keeping the date casting, and then adding the following serializeDate() method to the HasUniquePeriods trait, has got it to the point I can at least go to bed without this keeping me awake. I think the accessor was basically signaling an additional update to Livewire and this was causing things to get even more out of wack.

Many thanks to you and @snapey for the help and getting me to look in places I was missing before!

For reference, here's the method I mentioned (I basically just removed the UTC "Z" flag at the end):

    protected function serializeDate(DateTimeInterface $date)
    {
        return $date->format('Y-m-d\TH:i:s.u');
    }

Reference: Laravel Docs - Date Serialization

Activity icon

Replied to Livewire Assuming Date Inputs Are In UTC

So yes and no, it's still pulling the time with the offset, but it doesn't continually add the offset, so the days will remain the same.

On the component rendering (from Livewire Devtools):

model: Object
    end_date: "2021-07-31"
    name: "2020 - 2021"
    start_date: "2020-08-01"

The when after updating start_date

model: Object
    end_date: "2021-07-31"
    name: "2020 - 2021"
    start_date: "2021-03-22T07:00:00.000Z"

Previously this would add the offset to the end_date as well and push it to the next day, so that part works at least. But this seems like a bigger issue since it's still adding the offset. I think @snapey was on the right path in that the JSON is being sent in UTC in the first place.

I'm also a little weary since, that trait is used in a couple of models, not just the ServicePeriods model.

Activity icon

Replied to Livewire Assuming Date Inputs Are In UTC

ServicePeriod.php

<?php

namespace App;

use App\Settings\GlobalSettings;

class ServicePeriod extends UniqueTimePeriod
{
    /**
     * {@inheritDoc}
     *
     * @var array
     */
    protected $guarded = [];

    /**
     * Return the uri to the resource
     *
     * @return string
     */
    public function path()
    {
        return route('service-periods.show', $this);
    }

    /**
     * {@inheritDoc}
     */
    protected function getAttributesForBeforeSplit() {
        return [];
    }

    /**
     * {@inheritDoc}
     */
    protected function getAttributesForAfterSplit() {
        $start = $this->dayAfter($this->end_date)->format('m/d/y');
        $end = $this->envelope->end_date->format('m/d/y');

        return [
            'name' => "$start - $end"
        ];
    }

    /**
     * Return a the model of the current service period
     *
     * @return ServicePeriod|null
     */
    public static function current()
    {
        return ServicePeriod::find(GlobalSettings::get(GlobalSettings::CURRENT_SERVICE_PERIOD_ID));
    }

    /**
     * Set this ServicePeriod as the current service period
     *
     * @return void
     */
    public function setCurrent()
    {
        GlobalSettings::set(GlobalSettings::CURRENT_SERVICE_PERIOD_ID, $this->id);
    }

    /**
     * Return if this ServicePeriod is the current service period
     *
     * @return boolean
     */
    public function isCurrent()
    {
        return $this->id == GlobalSettings::get(GlobalSettings::CURRENT_SERVICE_PERIOD_ID);
    }

    /**
     * Return invoices associated with this service period
     *
     * @return \Illuminate\Database\Eloquent\Collection
     */
    public function invoices()
    {
        return $this->hasMany(Invoice::class);
    }
}

The UniqueTimePeriod parent class just uses a trait, and the only things that would apply here from that trait are the following


    /**
     * Initialize the trait
     *
     * @return void
     */
    public function initializeHasUniquePeriods()
    {
        $this->dates[] = 'start_date';
        $this->dates[] = 'end_date';

        $this->casts['period'] = CarbonPeriodCast::class;
    }

    /**
     * Accessor returns end_date attribute as end of day
     *
     * @param string|Carbon $value
     * @return Carbon
     */
    public function getEndDateAttribute($value = null)
    {
        return $value ? \Carbon\Carbon::parse($value)->endOfDay() : null;
    }
Activity icon

Replied to Livewire Assuming Date Inputs Are In UTC

@snapey Is there a way to adjust this? I'm sure you're right.

Activity icon

Replied to Livewire Assuming Date Inputs Are In UTC

@neilstee Here is the model, but it's not an issue with persisting the data is the hydration of the data on input that's the problem.

###ServicePeriodsTable.php

<?php

namespace App\Http\Livewire;

use App\ServicePeriod;
use App\Traits\HasEditableRows;
use Livewire\Component;

class ServicePeriodsTable extends Component
{
    use HasEditableRows;

    protected $model_class = ServicePeriod::class;

    protected function rules()
    {
        return [
            'model.name' => ['nullable'],
            'model.start_date' => ['nullable'],
            'model.end_date' => ['nullable']
        ];
    }

    public function render()
    {
        return view('livewire.service-periods-table', [
            'service_periods' => ServicePeriod::query()
            ->orderBy('start_date')
            ->get()
        ]);
    }
}

HasEditableRows.php (trait)

<?php

namespace App\Traits;

use App\Exceptions\NotImplementedException;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;

trait HasEditableRows
{
    use FlashesCRUDStatus, AuthorizesRequests;

    public function initializeHasEditableRows() {
        $this->listeners = [
            'newModel' => 'showCreateForm',
            'deleteModel' => 'delete'
        ];
    }

    /**
     * Index of row being edited
     *
     * @var int|null
     */
    public $editedRowIndex = null;

    /**
     * Details of model being edited
     *
     * @var Model
     */
    public $model = null;

    /**
     * Name of field to be used for flashing CRUD messages
     *
     * @var string
     */
    protected $flash_field = 'name';

    /**
     * Check that model class is set
     *
     * @throws NotImplementedException
     * @return void
     */
    protected function checkModelClassSet()
    {
        if (! $this->model_class) {
            throw new NotImplementedException('Model type has not been defined in the base class. Please add a protected $model_type attribute.');
        }
    }

    /**
     * Show the new model modal
     *
     * @return void
     */
    public function showCreateForm()
    {
        $this->resetForm();

        $this->dispatchBrowserEvent('new-model');
    }

    /**
     * Cancel creating a model and close modal
     *
     * @return void
     */
    public function cancelCreate()
    {
        $this->resetForm();
    }

    /**
     * Store a new model in the database
     *
     * @return void
     */
    public function store()
    {
        $this->checkModelClassSet();
        $this->authorize('create', $this->model_class);

        $model = $this->model_class::create($this->validate()['model']);
        $this->dispatchBrowserEvent('close-modal');
        $this->dispatchBrowserEvent('flash', $this->getAddMessage($model->{$this->flash_field}));

        $this->resetForm();
    }

    /**
     * Set the given row to edit mode
     *
     * @param array $model
     * @param int $index
     * @return void
     */
    public function editRow($model, $index)
    {
        $this->model = $this->retreiveModel($model['id']);
        $this->editedRowIndex = $index;
    }

    /**
     * Cancel a row being edited
     *
     * @return void
     */
    public function cancelEdit()
    {
        $this->resetForm();
    }

    /**
     * Update the model in the database
     *
     * @return void
     */
    public function update()
    {
        dd($this->model);
        $this->checkModelClassSet();
        $this->authorize('update', $this->model);

        $this->model->update($this->validate()['model']);
        $this->dispatchBrowserEvent('flash', $this->getUpdateMessage($this->model->{$this->flash_field}));

        $this->resetForm();
    }

    /**
     * Delete the model from the database
     *
     * @param array $args
     * @return void
     */
    public function delete($args)
    {
        $this->checkModelClassSet();
        $model = $this->retreiveModel($args['model']['id']);

        $this->authorize('delete', $model);
        $model->delete();
        $this->dispatchBrowserEvent('flash', $this->getDeleteMessage($model->{$this->flash_field}));

        $this->resetForm();
    }

    /**
     * Listener when a field is updated
     *
     * @param mixed $value
     * @return void
     */
    public function updated($value)
    {
        $this->resetErrorBag($value);
    }

    /**
     * Reset the form to a read-only state
     *
     * @return void
     */
    protected function resetForm()
    {
        if (method_exists($this, 'resetModel')) {
            $this->resetModel();
        } else {
            $this->model = new $this->model_class;
        }
        $this->editedRowIndex = null;
        $this->resetErrorBag();
    }

    /**
     * Retrieve the model from the database
     *
     * @param string $id
     * @return Model
     */
    protected function retreiveModel($id)
    {
        return $this->model_class::findOrFail($id);
    }
}

Livewire/Alpine input

<input
    x-data
    x-ref="input"
    x-init="new Pikaday({
        field: $refs.input,
        format: 'DD/MM/YY',
        onSelect: function(dateText) {
            @this.set('model.start_date', moment(dateText))
            },
        })"
        type="text"
        value="{{ $model && $model->start_date ? $model->start_date->format('m/d/y') : today() }}"
        class="form-input block w-full pr-10 sm:text-sm sm:leading-5"
>
Activity icon

Started a new Conversation Livewire Assuming Date Inputs Are In UTC

I'm struggling to get a javascript date picker (pikaday) working using the example on the Livewire Site after some tweaking I finally got it working.

The issue is I have two inputs on the page to select a start and end date, when changing an input and the model is updated, it seems livewire is making the assumption that the times are being sent in UTC so it adds the offset to both model attributes. This is a problem because when it initially hydrates the model, it's already adding the offset, and if for some reason a user changes the end date, 3 times, 28 hours will have been added to the start time (changing it to a day later) without firing an input event so the in the input looks like it has not changed.

I was able to prevent this problem from happening by reverting the timezone setting in /config/app.php back to 'timezone' => 'UTC'. Obviously this isn't what I want to do, as all of stored timestamps are now off by 7 or 8 hours.

Here are the results of a dd() in the updatedModelEndDate($value) hook:

"Sat Aug 01 2020 14:00:00 GMT-0700"    //$this->model->start_date->toString()
"Tue Mar 23 2021 23:59:59 GMT-0700"   //$this->model->end_date->toString() 
"Tue Mar 23 2021 07:00:00 GMT+0000"  //Carbon::parse($value)->toString()
"2021-03-23T07:00:00.000Z"                     //$value

I'll be the first to admit that time has always been a pain point for me in programming, but I think there must be a config issue somewhere that I'm missing.

Any help would be much appreciated as I've been ripping my hair out on this one all weekend.

PS: As I said, I'm pretty sure this is a configuration issue, so I haven't posted any code, but can do that if it will help find a solution.

Feb
26
2 months ago
Activity icon

Commented on Leverage Algolia Places

I believe there was a comment about how this was a backlogged lesson that was recorded before the sunsetting was announced, (which seems obvious since it being 86* F in Toronto in February seems weird :) )

In the sunsetting article Algolia offers three alternatives to Places:

If you are a Places customer, from the entire Algolia team, we’d like to apologize for any inconvenience this may cause you. We’re committed to making the transition as smooth as possible and that’s why we’ll continue to support Places until May 31st 2022. To help get you started, we provided some potential alternatives:

Mapbox Google Places Geocode Earth

I think the basics of what's being shown (integrating a location lookup api into the weather app) doesn't change, there's just a little extra work putting the pieces together. But we're programmers, that's what we do! ;)

Jan
12
3 months ago
Activity icon

Replied to View Laracasts Lessons By Date

Perfect! Thanks!

Activity icon

Started a new Conversation View Laracasts Lessons By Date

Is there a way to view Laracasts lessons by date? I typically start by going to the "What's new" page and this typically shows only the last 6 episodes. Most of the time I'm able to visit every weekday so it isn't a problem. On the rare occasion I am not able to visit for several days and all six episodes are new, I can't find a way to find a full list of episodes by date to make sure I didn't miss one.

Am I totally missing somewhere else this list might exist?

Nov
28
5 months ago
Activity icon

Started a new Conversation Livewire "casts" (hydrating And Dehydrating) A Value Object On A Related Model

I am in the process of adding Livewire functionality to the forms in my project. I've been successful so far, but have come across an issue with trying to get a value object to populate in an input. In my project a Funder has a polymorphic relationship to a Contact, and a contact has a phone_number attribute which the Contact class casts to a PhoneNumber value object.

I'm able to get the object itself into the input (i.e., the input reads [object Object]), but I'm having the hardest time getting the actual value to display and bind to the model.

FunderForm.php

<?php

namespace App\Http\Livewire;

use App\Funder;
use App\Rules\Phone;
use App\Traits\FlashesCRUDStatus;
use App\ValueObjects\PhoneNumber;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Livewire\Component;

class FundersForm extends Component
{
    use FlashesCRUDStatus, AuthorizesRequests;

    //Form Models
    public $funder;
    public $contact;
    public $address;

    //Form Fields
    public $name;
    public $is_active;

    public function rules()
    {
        return [
            'name' => ['required', 'max:90', 'min:5'],

            'contact.first_name' => ['required', 'max:45'],
            'contact.last_name' => ['required', 'max:45'],
            'contact.phone' => ['required', new Phone],
            'contact.email' => ['required', 'email'],

            'address.street' => ['required', 'max:100'],
            'address.city' => ['required', 'max:45'],
            'address.state' => ['required', 'max:2'],
            'address.postal_code' => ['required', 'min:5', 'max:10'],
        ];
    }

    public function mount(?Funder $funder = null)
    {
        $this->funder = $funder;
        $this->contact = $funder->contact;
        $this->address = $funder->address;

        $this->name = $funder->name;
        $this->is_active = $funder->is_active ?? true;
    }

    // ...

    public function hydrateContact($value)
    {
        $this->contact->phone = PhoneNumber::fromUnformatted($value);
    }

    public function dehydrateContact($value)
    {
        $this->contact->phone = $value->phone->asUnformatted();
    }
}

funders-form.blade.php (partial)


    <x-forms.section title="Funder Contact" subtitle="Enter contact information for this funder.">

           <x-forms.input
            wire:model.lazy="contact.email"
            required
            type="email"
            :placeholder="__('contacts.email_placeholder')"
            class="col-span-6 sm:col-span-3"
        >@lang('app.Email')</x-forms.input>

        <x-forms.input
            wire:model.lazy="contact.phone"
            required
            type="tel"
            :placeholder="__('contacts.phone_placeholder')"
            class="col-span-6 sm:col-span-3"
        >@lang('app.Phone')</x-forms.input>
    </x-forms.section>

In this excerpt I included the email field which is just a string and displays correctly in the form, to show the set up of the input component.

I'm not even sure if I've set up the mount() method correct for this situation. If I add the line <p>{{ $contact->phone->asUnformatted() }}</p> to the form, it does display correctly, but I can't figure out how to bind the data to the $contact attribute of the Livewire component. Any help would be appreciated.

Nov
24
5 months ago
Activity icon

Replied to Anonymous Component Props Always Equal To Default Value

Oof. When I said I didn't do anything else to the Input.php class other than rename the class, I meant it. I only changed the file name and not the class name. Sometimes you just want to bang your head against the desk when you make silly mistakes like that. Thanks @rodrigo.pedra! And thank you, @mvd for trying to help too!

Activity icon

Replied to Anonymous Component Props Always Equal To Default Value

I did use the artisan command to create it, but I've renamed the class from Input.php to OLDInput.php to break the link. I didn't do anything else though (like changing the namespace). I'll delete the file and try again. Unfortunately I won't have access to that computer for a couple of hours to try it, but you make a great point!

Activity icon

Replied to Anonymous Component Props Always Equal To Default Value

Recreating the file initially worked, but when I renamed the new component from test.blade.php to input.blade.php, it stopped working. I even swapped the file names (renamed test to input and input to test) then set some of the form's inputs to test and the others I left alone. Only the inputs that reference <x-forms.test /> (even though this was the original input.blade.php) show up correctly.

I've cleared my view cache and cleared the browser cache several times, is there a cache somewhere I'm missing?

Nov
23
5 months ago
Activity icon

Replied to Anonymous Component Props Always Equal To Default Value

@mvd, thanks for the reply! Below is the entire input.blade.php file.

input.blade.php

@props([
    'prepend' => null,
    'append' => null,
    'type' => 'text'
])

<div class="{{ $attributes->get('class') }}">
    <label for="{{ $attributes->wire('model')->value() }}-input" class="block text-sm font-medium leading-5 text-gray-700">{{ $slot }}</label>
    <div class="mt-1 relative rounded-md shadow-sm">
        @if($prepend)
            <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
                <span class="text-gray-500 sm:text-sm sm:leading-5">
                    {{ $prepend }}
                </span>
            </div>
        @endif
        <input
            {{ $attributes->except('class') }}
            id="{{ $attributes->wire('model')->value() }}-input"
            type="{{ $type }}"
            data-lpignore="true"
            @error( $attributes->wire('model')->value() )
                class="form-input block w-full {{ $append ? 'pr-22' : 'pr-10'}} {{ $prepend ? 'pl-7' : '' }} border-red-300 text-red-900 placeholder-red-300 focus:border-red-300 focus:shadow-outline-red sm:text-sm sm:leading-5"
                aria-invalid="true"
                aria-describedby="{{ $attributes->wire('model')->value() }}-error"
            @else
                class="form-input block w-full sm:text-sm sm:leading-5 {{ $prepend ? 'pl-7' : '' }} {{ $append ? 'pr-12' : '' }} disabled:bg-gray-100"
            @enderror
            />
        @if($append)
            <div class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
                <span class="text-gray-500 sm:text-sm sm:leading-5" id="price-currency">
                {{ $append }}
                </span>
            </div>
        @endif
        @error( $attributes->wire('model')->value())
            <div wire:key="{{ $attributes->wire('model')->value() }}_error_svg" class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
                <svg class="h-5 w-5 text-red-500" fill="currentColor" viewBox="0 0 20 20">
                    <path fill-rule="evenodd"
                        d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z"
                        clip-rule="evenodd" />
                </svg>
            </div>
        @enderror
    </div>
    @error( $attributes->wire('model')->value() )
        <p wire:key="{{ $attributes->wire('model')->value() }}_error" class="mt-2 text-sm text-red-600" id="{{ $attributes->wire('model')->value() }}-error">{{ $message }}</p>
    @enderror
</div>
Activity icon

Started a new Conversation Anonymous Component Props Always Equal To Default Value

I have an anonymous component and every @prop is set to either the default (if set) or null (if not set).

input.blade.php (snippet)

@props([
    'prepend' => null,
    'append' => null,
    'type' => 'text'
])

contracts-form.blade.php (snippet)


<x-forms.input
	wire:model.lazy="initial_payment"
	min="0"
	step="0.01"
	type="number" 	//**prop set**
	prepend="$"		//**prop set**
        :placeholder="__('contracts.initial_payment_placeholder')"
        class="col-span-6 sm:col-span-3"
>@lang('app.Initial Payment')</x-forms.input>
	

Dev tools output

<input wire:model.lazy="initial_payment" min="0" step="0.01" placeholder="Enter contract initial payment" id="initial_payment-input" type="text" class="form-input block w-full sm:text-sm sm:leading-5   disabled:bg-gray-100">

You'll see in the dev tools output type="text" and the prepend prop is missing.

Not sure if this is a result of converting a full component (view and class) to an anonymous component or if I'm just missing something. Any help would be appreciated.

Nov
13
5 months ago
Activity icon

Commented on Weak Maps

Just pointing this out for people who haven't upgraded to PHP 8 yet, but the null coalescing assignment operator (??=) was introduced in PHP 7.4, so you can use that tip from the video prior to upgrading to PHP 8

Thanks for these videos as new versions of PHP or Laravel come out, they're super helpful providing concrete examples and explaining the history of how things were done vs how they can be done.