Search code examples
phplaravellaravel-novaeloquent-relationship

Is there a way to alter the attach page to enhance specificity for a particular type of relationship?


I have a Laravel 9 project with a Nova 4 admin panel and the following set of relationships: there's the Attribute entity that defines a particular attribute (e.g. Project Type, Rating, etc.). A typical attribute is linked to several values that it can have (e.g. Project Type 1, Project Type 2, Project Type 3). These values are represented by the Option entity, thus there's a one-to-many relationship between attributes and options. Finally, there the Contractor entity, which these attributes can be attached to, so we have a many-to-many relationship between contractors and options.

Back to Nova, I wanted to be able to attach options to a contractor I select in the contractors detail page and also to attach contractors to a selected option in the options detail page. Using the BelongsToMany Nova class I connected these two entities, but the problem is that when attaching an option to a contractor, it shows only one dropdown with all options available without specifying attributes. Is there a way to have two dropdowns, one for attributes, and another one for options, which would be depending on which attribute has been selected?

enter image description here


Solution

  • You can define a BelongsToMany relation, add your custom fields inside and then hide the original fields like so:

    BelongsToMany::make('Options')->fields(function () {
        return [
            Select::make('Attribute')
                ->options(\App\Models\Attribute::query()
                ->toArray())
            ),
            Select::make('Options')->dependsOn('attribute', function (Select $field, NovaRequest $request, FormData $data) {
                $field
                    ->options(\App\Models\Option::query()
                      ->where('attribute_id', $data->attribute)
                      ->get()
                      ->toArray()
                );
          }),
        ];
    })->hide(),