Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

guybrush_threepwood's avatar

Nova 4: BelongsTo field with dependsOn retains old value after refresh

I'm experiencing the following issue while working with Nova 4.26.3:

I have two BelongsTo fields, Country and Salesperson. Salesperson dependsOn Country:

BelongsTo::make('Country', 'country', Country::class),

BelongsTo::make('Salesperson', 'salesperson', Admin::class)
    ->dependsOn(['country'], function (BelongsTo $field, NovaRequest $request, FormData $formData) {
        $field->relatableQueryUsing(function (NovaRequest $request, Builder $query) use ($formData) {
            $query
                ->whereHas('countries', function (Builder $query) use ($formData) {
                    $query->where('countries.id', $formData['country']);
                });
        });
    })
    ->nullable(),

Problem is, if I select a Country followed by a Salesperson and then I change the Country again, the Salesperson field appears blank but retains the last Salesperson ID and validation fails ("This Salesperson may not be associated with this resource.").

Step 1. Step 2. Step 3.

Is there a fix for this? I tried setting the field value programatically to NULL but it isn't working.

I'm dreading the alternative: Replacing the second belongsTo with a select field, adding lots of unnecessary code and having to create a custom validation Rule for the field.

0 likes
1 reply
guybrush_threepwood's avatar
Level 33

Apparently Nova maintainers believe this is "normal behaviour" for a belongsTo field: That you can't submit the form after changing the parent field.

I ended up solving it by using a BelongsTo field for everything except forms, and another Select field for the forms.

Here's the code in case someone's interested:

BelongsTo::make(__('Salesperson'), 'salesperson', Admin::class)
    ->exceptOnForms(),
    
Select::make(__('Salesperson'), 'salesperson_id')
    ->dependsOn(['country'], function (Select $field, NovaRequest $request, FormData $formData) {
        $admin = Auth::guard('admin')->user();
        $options = \App\Models\Admin::sales()
            ->whereHas('countries', function (Builder $query) use ($formData) {
                $query->where('countries.id', $formData['country']);
            })
            ->when($admin->isSales(), function (Builder $query) use ($admin) {
                $query->where('id', $admin->id);
            })
            ->pluck('name', 'id');
        $field->options($options);
    })
    ->nullable()
    ->rules([
        'nullable',
        new SalespersonRule(),
    ])
    ->onlyOnForms(),

This in turn made me create a custom validation rule, in order to ensure that child records can't be tampered with (BelongsTo DependsOn does this automatically):

<?php

namespace App\Rules;

use App\Models\Admin;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Auth;

class SalespersonRule implements ValidationRule
{
    /**
     * Run the validation rule.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @param  \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString  $fail
     * @return void
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        $admin = Auth::guard('admin')->user();

        $query = Admin::sales()
            ->whereHas('countries', function (Builder $query) {
                $query->where('countries.id', request()->input('country'));
            })
            ->when($admin->isSales(), function (Builder $query) use ($admin) {
                $query->where('id', $admin->id);
            })
            ->where('id', $value);

        if (! $query->exists()) {
            $fail(__('Please select a valid Salesperson.'));
        }
    }
}

Please or to participate in this conversation.