Joel
Joel

Reputation: 1670

Selected options in multi select based on old() OR existing data

I have two models with a many-to-many relationship: Project and User.

When creating or editing a User the below multi select field partial is included in the view.

It loops through the projects and checks if there is data in old(). If there is data in the old() it compares the project $id to the array in old() and adds the selected attribute if it exists. If there is no data in old it plucks the existing $user's project ids into an array - applying the selected attribute if it exists.

<select class="form-control" id="projects" name="projects[]" multiple>
    @foreach($projects as $id => $name)
        <option value="{{ $id }}" 
        @if(old("projects")) 
            @if(in_array($id, old("projects"))) 
                selected="selected" 
            @endif 
        @else
            @if(in_array($id, $user->projects->pluck('id')->toArray())) 
                selected="selected" 
            @endif
        @endif > {{ $name }}</option>
    @endforeach                
</select>

So this works - but I am wondering if there is a better way to do it. The nested loops feel messy.

Is there a cleaner and more efficient way to accomplish this using blade?

Upvotes: 1

Views: 261

Answers (1)

Anwar
Anwar

Reputation: 4246

You could use a combination of code factoring using one-liners, Laravel collection, and Blade directive @php to add an extra separation layer between the logic and the display:

<select class="form-control" id="projects" name="projects[]" multiple>
    @foreach($projects as $id => $name)
        @php
            $selected = collect(old('projects'))->contains($id) || $user->projects->pluck('id')->contains($id) ? 'selected="selected"' : '';
        @endphp
        <option value="{{ $id }}" {{ $selected }}> {{ $name }}</option>
    @endforeach                
</select>

Blade directive @php @endphp let you work as you were at home. Laravel collect can also work with null values, so if your old('projects') is null, the collection will be an empty array and it will not pass the ->contains($id) statement. This saves you another check.

Hope it inspires you.

Upvotes: 3

Related Questions