How to ensure unique ID in Laravel Blade?
Asked Answered
R

3

5

Let's imagine I have a blade component such as:

<input type="text" id="foo" name="{{$name}}"/>
<script>
$('#foo').whatever
</script>

IRL, this component is far more complicated. You could imagine a long form with plenty of fields with generic names like name, description, owner...

Then I use this component multiple times, again I propose a foreach but we could imagine something else in which I cannot use an iterator to provide an id to my component:

@foreach($items as $item)
    @component('foo')
    @endcomponent
@endforeach

How can I ensure the uniqueness of the id?

One perhaps bad solution would be to use a local variable:

@php($id = uniqid())
<input type="text" id="{{$id}}" name="{{$name}}"/>
<script>
$('#{{$id}}').change(whatever)
</script>

Is there a better way?

Rubefaction answered 5/6, 2019 at 18:52 Comment(3)
Is that last part of code inside component fooBlaise
Just use the iterator in your foreach loop as a suffix to your id. E.G #foo--1 #foo--2 etc. $loop->iteration laravel.com/docs/5.8/bladeTungstite
This is just an example, my component is far more complicated, and I used a loop just to say, well I am calling multiple time that componentRubefaction
C
5

I'd pass the item to the component:

@component('foo', ['item' => $item])

Which allows you to do this in it:

<input type="text" id="foo_{{ $item->id }}"/>
Clothing answered 5/6, 2019 at 18:56 Comment(2)
Or, if $item doesn't have an id, you can do $items as $id => $item (or $index, etc)Perfoliate
Its very very boilerplate and IMHO it is the callee responsibility to ensure its id are uniqueRubefaction
S
2

Had the same need, found this answer, and as the OP said, I prefer to think that since the components needs it, it should handle it.

I came up with this alternative.

// resources/views/components/button.blade.php
@php
    $yourLibNameId = uniqid();
@endphp

<button data-your-lib-name-id="{{ $yourLibNameId }}">{{ $slot }}</button>

@push("script")
    <script type="text/javascript" defer="true">
        document.addEventListener("DOMContentLoaded", function() {
            const button = document.querySelector("[data-your-lib-name-id='{{ $yourLibNameId }}']");

            if (button instanceof HTMLElement) {
                button.addEventListener("click", function() {
                    console.log("clicked");
                });

                // or do whatever needed to initialize the button...
            }
        });
    </script>
@endpush

To summarize:

  • Instead of relying on an id attribute, I use a data-x attribute to not interfer with the id, and give a proper scope to the use of this data
  • I assume the user will provide a @push("script") directive at the right place in his layout or view

I am about to create a component library for Material Components Web, so this is what I will use to proceed (hence the your-lib-name).

Hope it help folks keeping their components the most isolated possible.

Slagle answered 19/4, 2020 at 21:17 Comment(0)
F
1

If we can assume the ID only needs to be referenced within the component (e.g. a field and a label together) and it doesn't matter anywhere else what the ID is as long as its unique... uniqid looks like it should be fine, but you could also use \Illuminate\Support\Str::random() as part of the ID. Obviously either of those would change with every render, and I would personally favor including some meaningful text as well (e.g. 'name_field_'.Str::random()).

Alternatively, a singleton could be used to generate and track IDs used and make sure they're not reused. Something like:

class UniqueIdTracker
{
    protected $idTracking = [];
    public function __invoke($prefix)
    {
        $increment = $this->idTracking[$prefix] ?? 0;
        $this->idTracking[$prefix]++;
        return $prefix . $increment;
    }
}

Which would then be called with app(\Namespace\UniqueIdTracker::class)('prefix_'). (This could be improved by wrapping it in a helper function or something).

I would also note that AlpineJS would probably be a good fit for OP's use case, as the script can attach to the element without ID.

Felishafelita answered 29/3, 2021 at 14:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.