Get selected values from database in checkboxes (Laravel)

Published 2 weeks ago by Tangaye

I'm working on a laravel application. In this application I have three tables:

subjects

id | name
-- | ----
01 | maths
02 | english

divisions

id | name
-- | ----
01 | Senior High
02 | Junior High

division_subject pivot table

division_id | subject_id
--- | ---
01 | maths
02 | english

A subject can have many divisions, so, in my form I have a list of all divisions as checkboxes. If asubject is taught in a single division a single division will be checked. If the subject is taught is many divisons all the divisions the subject is taught in will be checked also. Now this is working fine when inserting with no problems.

This is how the form looks to insert records:

enter image description here

After records are inserted this is how they are displayed in the table:

enter image description here

Html code for displaying table:

<tbody id="subjects">
@foreach($subjects as $subject)
    <tr>

        <td data-type="text" data-name="name" class="name" data-pk="{{$subject->id}}">{{$subject->name}}</td>

        <td>
            <!-- If a subject belongs to a division or divisions list all the divisions
            that belongs to the subject -->
            @if(count($subject->divisions))
                @foreach($subject->divisions as $division)

                    <a href="#" data-type="checklist" data-value="{{$division->id}}" data-title="Select divisions" data-name="division" class="division" data-pk="{{$division->id}}" role="button">
                        <span class="badge label-primary">{{$division->name}}</span>
                    </a> 

                @endforeach
            @endif
        </td>

        <td>
            <a class="edit-modal" data-id="{{$subject->id}}" data-name="{{$subject->name}}" data-toggle="tooltip" title="Edit" href="#" role="button">
                <i class="glyphicon glyphicon-edit text-info"></i>
            </a>
        </td>
        <td>
            <a id="delete" data-id="{{$subject->id}}" data-toggle="tooltip" title="Delete" href="#" role="button">
                <i class="glyphicon glyphicon-trash text-danger"></i>
            </a>
        </td>

    </tr>
@endforeach

Now I want when I click on the edit button a bootstrap dialog will pop out and show details for the record to be edited. If the subject has divisions assigned or a division assigned, than all the division assigned to the subject and stored in the pivot table should be checked. And those divisions that are not assigned unchecked.

To list a the subject in the form I'm using a view composer in the App service provider to pass the division data to my view:

view()->composer('subjects.show', function ($view){

        $view->with('divisions', \App\Division::all());
    });

Now in my form this is how I'm listing the divisions as seen in the picture above:

<div class="form-group">

    <label for="division">Level</label>
    <p class="text-muted">Please select the division(s) the subject is taught within.</p>
    @foreach($divisions as $division)
        <label class="checkbox-inline">
            <input type="checkbox" id="division_id" name="division_id[]" value="{{$division->id}}"> {{$division->name}}
        </label>
    @endforeach                            
</div>

How can I refactor this to checked all values that are assigned to a subject and have those values which are not assign unchecked?

Best Answer (As Selected By Tangaye)
sobhanattar

@Tangaye Hi Sorry for being late answering the question, I thought that if some one mention me in a discussion, then I'll get an alert on my email which is not the case.

For the first part, eager loading is absolutely the better way to go as it costs you only 2 query instead of a query/loop in your index view. But maybe the slowness of the view, is related to something else.

So stay with eager loading for the sake of your application performance.:)

You can see the difference between number of queries by installing this

For the second part of your question, if I understand it correctly you have divisions and subjects and there is a relation between these two that is being stored in subject_division table.

In other words you should have an edit method with following signature in SubjectsController.php

public function edit(Request $request, Subject $subject)

As you already knew, here the $subject variable is the one you want to show info about and show which divisions it has. So your method will be something like this:

public function edit(Request $request, Subject $subject)
{
    //after validation

    $selectedDivisionsOfThisSubject = $subject->divisions()->get();
    $divisions = Division::all();
    
    return view('subjects.show', compact('subject',     'selectedDivisionsOfThisSubject', 'divisions'));
}

In this method you pass $subject so you have info like $subject->name. $divisions give you the ability to show all divisions for each subject by putting this piece of code

@foreach($divisions as $division)
    <label class="checkbox-inline">
    <input type="checkbox" id="division_id" name="division_id[]" value="{{$division->id}}"> {{$division->name}}
    </label>
@endforeach

So now you have $subject info and list of divisions from foreach on $divisions. Now the only thing you passed and still not used is $selectedDivisionsOfThisSubject which holds the ids of divisions that are selected for this subject and you can dd() it to see how it stores the data and then used it in your code. Generally it will be a collection and you can easily find your path around.

fransiskusbenny
<input type="checkbox" id="division_id" name="division_id[]" value="{{$division->id}}" {{ $division->id == $value_from_database ? 'checked' : '' }}> 

or from pivot

<input type="checkbox" id="division_id" name="division_id[]" value="{{$division->id}}" {{ $subject->divisions->contains($division->id) ? 'checked' : '' }}> 
Tangaye

@fransiskusbenny I get this error when I do the second solution suggested, because I don't seem to understand the first.

Undefined variable: subject
bunnypro

you can pass the related divisions to the modal by set it as data-* in modal button trigger, and then set the checked checkbox with javascript.

http://getbootstrap.com/javascript/#modals-related-target

// inside $subjects foreach
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#yourEditModal" data-divisions="{{ $subject->divisions->pluck('id')->toJson() }}">Edit</button>

// do your javascript to check all related division checkbox
Tangaye

@bunnypro I'm not that good with javascript and have not the slightly idea on how you want me to accomplish this. Can you please be a little bit practical? Also know that I want the list of all the divisions and the ones assigned to the subject to be edited should be checked.

sobhanattar

@Tangaye I'm not sure if I followed your code correctly or not,or maybe that's because you didn't send us you model. What I can say is there is actually two problem is exists with your code:

  1. you are not eager loading your model so for every @foreach($subject->divisions as $division) in your code there will be a query executed against the database. This means that if you have 10/100/1000 divisions you have this number of query. For more info please see here

  2. and for selecting checked ones you can use in_array(...) or contains()

@foreach($divisions as $division)
    <label class="checkbox-inline">
    <input type="checkbox" id="division_id" name="division_id[]" value="{{$division->id}}" {{ in_array($division->id, $array_of_values_you_fetched_from_database_as_seleted_items) ? 'checked' : '' }}> {{$division->name}}
        </label>
    @endforeach                           

Hope it helps

Tangaye

@sobhanattar Thanks for being a bit explicit. This is what I have in my controller to display records in my table:

public function index(Subject $subject)
{
    //
    $subjects = Subject::all();
   
    return view('subjects.show', compact('subjects'));
}

If it is best practice and is advisible I can refactor to this:

 $subject = Subject::with('divisions')->get();

The reason I didn't do it that way is that I realize that the page loads a bit slower when I do that. Like it's loading all the subjects and divisions at once. But anyway if it's best practice as I sad I will go along.

concerning the checked values

You said I should do this:

{{ in_array($division->id, $array_of_values_you_fetched_from_database_as_seleted_items) ? 'checked' : '' }}

But I'm thinking if I should make an ajax call to get the divisions assigned to the subjects. If the divisions are many, how do I pass the array of divisions returned to the method you suggested. Will appreciate some practical examples.

sobhanattar

@Tangaye Hi Sorry for being late answering the question, I thought that if some one mention me in a discussion, then I'll get an alert on my email which is not the case.

For the first part, eager loading is absolutely the better way to go as it costs you only 2 query instead of a query/loop in your index view. But maybe the slowness of the view, is related to something else.

So stay with eager loading for the sake of your application performance.:)

You can see the difference between number of queries by installing this

For the second part of your question, if I understand it correctly you have divisions and subjects and there is a relation between these two that is being stored in subject_division table.

In other words you should have an edit method with following signature in SubjectsController.php

public function edit(Request $request, Subject $subject)

As you already knew, here the $subject variable is the one you want to show info about and show which divisions it has. So your method will be something like this:

public function edit(Request $request, Subject $subject)
{
    //after validation

    $selectedDivisionsOfThisSubject = $subject->divisions()->get();
    $divisions = Division::all();
    
    return view('subjects.show', compact('subject',     'selectedDivisionsOfThisSubject', 'divisions'));
}

In this method you pass $subject so you have info like $subject->name. $divisions give you the ability to show all divisions for each subject by putting this piece of code

@foreach($divisions as $division)
    <label class="checkbox-inline">
    <input type="checkbox" id="division_id" name="division_id[]" value="{{$division->id}}"> {{$division->name}}
    </label>
@endforeach

So now you have $subject info and list of divisions from foreach on $divisions. Now the only thing you passed and still not used is $selectedDivisionsOfThisSubject which holds the ids of divisions that are selected for this subject and you can dd() it to see how it stores the data and then used it in your code. Generally it will be a collection and you can easily find your path around.

Tangaye

@sobhanattar thanks I got it working now. But I used ajax to to fetch the $selectedDivisionOfThisSubject and passed that to my view. Also I utilize the in_array() method you suggested in your first answer which lead me to returned the selected divisions like this $selectedDivisionOfThisSubject->toArray(). :heart_eyes: :kissing_closed_eyes: :wink:

sobhanattar

@Tangaye I don't know why it's not working, as I have same code that is working. Maybe you can send me your tables with dummy data, and then I do the job on my side and send you the final code.

Because by having the subject, divisions and selectedDivisions you should not go the ajax way

minjon
minjon
1 week ago (40,860 XP)

This is how I usually organize my code:

@foreach ($divisions as $division)
    
    <label class="checkbox-inline">

        <input type="checkbox" name="division_id[]" id="division_id_{{ $division->id }}" value="{{ $division->id }}"

            @if ($ids = $subject->divisions->pluck('id')->toArray())

                @foreach ($ids as $division_id)
                        
                    {{ $division->id == $division_id ? 'checked' : '' }}
                    
                @endforeach

            @endif
        />
            
       {{ $division->name }}

    </label>
    
@endforeach
Tangaye

@sobhanattar I don't selectedDivision in order to get that I had to make an ajax request. Please know that I'm using a pop up bootstrap model for editing, which means I'm not loading out another view to edit the record. After I have send the id to the edit method and have gotten the values I want returned. I return a partial view with those values (subjects,selectedDivisios.divisions`) into my modal for editing. Hope this gives understanding. Please let me know if there's a better of cleaner way to do it. Thanks so much for the effort.

sobhanattar

@Tangaye do you call public function edit(Request $request, Subject $subject) in your ajax call and get partial HTML to show in modal?

If that is the case you are passing $subject id as parameter to edit, so can have $subjectDivisions by calling $subject->divisions()->get() in that same edit method and pass it in partial view. I assume that your ajax call is waiting for html to receive.

In which divisions() is a belongsToMany relationship that shouldbe declared in Subject Model.

Tangaye

@sobhanattar that's right! Am I going about it the right way?

Sign In or create a forum account to participate in this discussion.