If all you want to do is have the width of the input equal the width field defined in your InputBox class, you can do so without involving AlpineJS. You’re making things much harder on yourself setting things up like this, but we’ll get it sorted!
First, a few recommendations:
- A lot of the “magic” that Laravel and Livewire do behind the scenes to make things work is based upon following certain conventions. One such convention is that your class name should match your file name. So I recommend renaming your Builder class to InputBox. In fact, Livewire may not work unless you do this.
- It’s my opinion that variable names should be as descriptive as possible. When you look back at your code 6 months from now, you’re not going to remember all the blood, sweat, and tears you put into making your code work. But you can take steps which make it easier on you or other developers down the line. So instead of shortening your variable name to
$cInput
, I would recommend writing out the full name, so you can know immediately what it is, even 6 months from now (it’s a good habit to develop, even if you never plan to look at this code again).
- Remove the $ from your variable name inside the
$rules
declaration. This is another one of those things based on convention.
- Remove the $ from the variable name when accessing it as a class field. In other words change this:
$this->$cInputs = $myInputs;
to this: $this->cInputs = $myInputs;
. This is a PHP convention. Whenever you access a variable with $this
leave the $ out of the variable name.
- You may need to remove the
@
from @dd
. I’m not sure what this is meant to be doing, but simply calling the dd
function is enough.
- Your render function in your Livewire class is returning the wrong view. This is another Livewire feature based around convention. Your Livewire view is called
input-box
, not builder
, so this will cause problems for you.
- This is a more general programming convention, but typically class methods start with a lowercase letter, and static methods start with a capital letter. This won’t cause problems with Livewire, but is another good programming habit to develop.
- Your Livewire view component should access class fields using the same $this syntax as you would use in the class itself. So change
name = "{{ $cInput->name }}"
to name = "{{ $this->cInput->name }}"
- You’re using some of your Alpine functions incorrectly. Change
$entangle
to @entangle
. You could alternatively use $wire.entangle
.
- You are trying to directly access
cInput.width
inside of your Alpine x-data
. Keep in mine that AlpineJS and Livewire live in different worlds. They can only play together if you tell Alpine about Livewire using @entangle
, or the $wire
object. So until you entangle a livewire variable, alpine doesn’t know what cInput.width
is.
- The way you are defining the width attribute of your input is incorrect. If you want to bind the width to an Alpine variable, do it like so:
<input x-bind:[attribute]="[expression]">
, so more specifically: x-bind:width="top"
- Check out the AlpineJS documentation linked at the bottom of this post
- Another incorrect Alpine syntax is your ref accessor. Insted of
$xrefs.container
it should be $refs.container
Now for the implementation itself. I’m not entirely clear on what you’re trying to accomplish here, so you may need to provide more information if we are to find a solution that does what you want it to do. My understanding is that you are trying to render each element in $cInput
as its own input field of varying widths. If so, you are going to need a loop to iterate over the variable in your view:
@foreach($this->cInput as $input)
<input
name="{{ $input->name }}"
value="{{ $input->text }}px;" // You had this defined as text="", which is not a valid attribute. I don't know what this is meant to do, but it seems you are trying to set the value, so I changed to accordingly
class="{{ $input->class }}"
id="myInputField"
width="{{ $input->width }}"
/>
@endforeach
This implementation will list out each element in $cInput as an input with properties matching those defined in the model. However, it will not synchronize changes to the input’s value with the model. ie. changing what’s in the input will not do anything - this is pretty much just a readonly field in this state. If you want the model instance backing each input tag to update when the input value is changed, you’re going to need to rethink your implementation. I would recommend rewriting the Livewire component to handle only one instance of $cInput at a time, rather than trying to manage them all at once in a collection. You can still use a collection if you like (check out the documentation in the link at the bottom of this post, 2nd code snippet under “Binding Directly To Model Properties”). I’ll show you the method I recommend because it’s easier to grok, but it’s up to you how you want to implement it.
cinputs.blade.php
Mounts the Livewire InputBox component for each instance in your cInput collection
<div>
@foreach(\App\Models\cInput::all() as $cInput)
{{-- The colon (:) before the cInput prop tells Livewire to interpret the expression as PHP, but you could also leave out the colon and put $cInput inside curly braces like normal: cInput="{{ $cInput }}" --}}
<livewire:input-box :cInput="$cInput" />
@endforeach
</div>
InputBox.php
The Livewire class containing the core logic for this component
<?php
namespace App\Http\Livewire;
use App\Models\cInput;
use Livewire\Component;
class InputBox extends Component
{
public cInput $cInput;
protected $rules = [
'cInput.text' => 'required|string',
];
public function mount(cInput $cInput)
{
$this->cInput = $cInput;
}
// Binding the input to the $cInput model is enough to have the input display the right value, and also update when the input value is changed, but you will need to save the model to persist those changes to your database.
public function save()
{
// Validation is done here if you have some rules in place
$this->validate();
$this->cInput->save();
// If you want the width of each input to change based upon the value you type into it, you could also update that here, and Livewire should re-render with the new width
$this->cInput->update([
'width' => $this->cInput->text,
]);
}
public function render()
{
return view('livewire.input-box');
}
}
input-box.blade.php
The Livewire View component which models the cInput properties
<div>
<input
wire:model="cInput.text"
name="{{ $this->cInput->name }}"
class="{{ $this->cInput->class }}"
width="{{ $this->cInput->width }}px"
id="myInputField"
/>
{{-- You will need some way of triggering the model to persist changes. Using a button to call the save function is easy and performant, but you could also call save everytime the input content changes using wire:change="save" - this will call the save method every time you type something in the input, which may impact performance if you do this too much.. --}}
<button wire:click="save">Save</button>
</div>
I don’t have your models and data to test this code out with, but it should at least point you in the right direction. What will help you the most is taking a close look at the documentation for both Livewire and AlpineJS, which I’ve linked below.