1

I was following the article to bring up front end UI for Spatie/permissions.

article

I was able to understand every part but I cant understand a specific portion,

Please navigate to the Roles Part, (please search for 'roles.edit', it will take directly to the section )

In the Edit view the author is using the code,

<h5><b>Assign Permissions</b></h5>
    @foreach ($permissions as $permission)
        {{Form::checkbox('permissions[]',  $permission->id, $role->permissions ) }}
        {{Form::label($permission->name, ucfirst($permission->name)) }}<br>
    @endforeach

My understanding is that the form collective uses third parameter as checked field.

when I run the output passed to the third field

{{$role->permissions }}

I am getting results in this format

[{"id":1,"name":"Permission","guard_name":"web","created_at":"2019-08-04 05:53:14","updated_at":"2019-08-04 05:53:14","pivot":{"role_id":9,"permission_id":1}},

I am not sure how the laravel collective is parsing the result.

Authors Controller for edit

 public function edit($id) {
        $role = Role::findOrFail($id);
        $permissions = Permission::all();
        return view('roles.edit', compact('role', 'permissions'));
    }

Here is how I overcame this, btw I am not using collective

My Edit controller

 public function edit($id)
    {
        $role = Role::find($id);
        $roles_permissions = Role::findByName($role->name)->permissions;
        $permissions = Permission::all();

        return view('admin.userrole.role.edit', compact('role', 'permissions','roles_permissions'));
    }

My Blade file

<h4>Assign Permission</h4>
        <div class='form-group'>
            <p>
                Existing Permissions:
                @foreach ($roles_permissions as $item)
                <span class="badge badge-success"> {{$item->name}}</span>
                @endforeach
            </p>
            <p> {{$role->permissions}}</p>
            <select name="permissions[]" id="permissions" multiple class="form-control">
                @foreach ($roles_permissions as $item)
                <option value="{{$item->id}}" selected hidden></option>
                <span class="badge badge-success"> {{$item->name}}</span>
                @endforeach
                <option value="" selected>
                </option>
                @foreach ($permissions as $permission)
                <option value="{{$permission->id}}" checked="{{$role->permissions}}">{!!ucfirst($permission->name)!!}
                </option>
                @endforeach
            </select>
        </div>

I am sure that this is not the right way of achieving this. Please do let me know how do I populate the permissions in the select field.

Note: If devoting the question, kindly do put a comment why. So that I could improve my presentation. I do appreciate your effort. Thank you

apokryfos
  • 38,771
  • 9
  • 70
  • 114
mightyteja
  • 825
  • 1
  • 14
  • 38

1 Answers1

1

There are a couple of issues that should help you to get this working. The LaravelCollective form (HTML) library is fantastic, but it also takes a little getting used to.

On the controller side, you are currently sending a list of full permission objects back to the form from this line:

 $permissions = Permission::all();

Or, as the author's form is doing it, they are pulling just those permissions from the specific $role. Either way, the missing piece is that the controller is sending the full object back to the form, which won't work as it is currently coded. The select box needs just name and id.

So the controller should gather just those fields using pluck:

 $permissions = Permission::orderBy('name')->pluck('name', 'id');

Then, on your blade page, the choices in permissions will correctly line up with the select section:

{{Form::select('permissions[]', $permissions, null, [//classes, placeholder, multiple, etc] ) }}

Note a few things here - the $permissions are the second parameter, not third. Also, you do not need to specify the $permission->id, this is automatically done with the Collective via form-model-binding. Instead, use null and it will bind on the user that you have bound to the form. If you are not using form model binding, you can write it yourself using the 3rd parameter instead of null:

 {{Form::select('permissions[]', $permissions, (isset($user->permission_id)? $user->permission_id: [null=>'Please Select']), [//classes, placeholder, multiple etc] ) }}

Form model binding is fantastic, and allows you to use null as above... it's not hard - you just need to open the form with the correct model. This is beyond the scope of this question, but take a look at the Collective docs for examples on how to do it.

Watercayman
  • 7,970
  • 10
  • 31
  • 49
  • Thanks for the detailed write up.. I am using laravel 5.8 and trying to avoid collective because of its limited support. if you dont mind coud you please explain me the same with normal form. – mightyteja Aug 04 '19 at 19:27
  • I used Collective in my answer because that was what was used in the example you showed in your question, and what the tutorial article used. I highly recommend using Collective for this as it matches the stuff the library uses - Collective's *other* products have limited support. HTML (Forms), however, has nearly 16K downloads per day and is absolutely supported - It's not perfect, but it is extremely widely used and quite helpful. – Watercayman Aug 05 '19 at 02:53
  • Thank you :). I have about 100 forms in my application. As of now will leave the old one intact and start using collective from now. Need to migrate them all to collective. Pretty big task – mightyteja Aug 05 '19 at 04:29
  • 1
    It is probably worth the effort - especially if you use form - model binding. It will make life much easier. I would be grateful if you could mark the answer as correct, please, as this will solve your issue :) – Watercayman Aug 05 '19 at 14:08
  • Thank you very much for your time I do really appreciate it. I was informed that shouldn't be using collective :(. I do appreciate if you could please share me any artilcle where the same model binding is done in regular form. Because I just dont want to blindly follow a packge. – mightyteja Aug 05 '19 at 17:35
  • I don't know of another automated way to bind the model - thats why most developers use collective. But, you can manually do it with the verbose standard HTML form using loops like you have in your question and then combine with an if check for `isset` on each iteration of the loop for the variable. If it is set, this will be the current value. A little like my last code example in my question - but a little more work doing it with the basic html forms. You can't bind this way, but you at least can check to see what the selected value is. – Watercayman Aug 05 '19 at 18:17
  • Something like `if (isset($user->permission_id) && $user->permission_id === $loopPermissionId) { // This would be the previously selected item, so mark as such in the standard HTML form }` I'm not sure how you have it all set up, but it is possible to do this manually if you can't use collective. :) – Watercayman Aug 05 '19 at 18:19
  • Thank you so much Bro, Will definitely look onto collective from future projects – mightyteja Aug 07 '19 at 23:37