Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Nova Belongsto Depend Laravel Package

orlyapps/nova-belongsto-depend

orlyapps/nova-belongsto-depend adds dependent BelongsTo fields to Laravel Nova. Selecting a parent option dynamically reloads child selects through AJAX, so related records stay filtered and relationship forms remain accurate and easy to use.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require orlyapps/nova-belongsto-depend

There is nothing else to wire up: no migrations, no config publishing, no manual provider registration. Nova's auto-discovery picks up the service provider and its vendor route. If composer require fails, the problem is almost never the package — it's Nova Composer credentials not being present in that environment (a fresh CI box or a new laptop is the classic case).

Where to look first, in this order:

  1. vendor/orlyapps/nova-belongsto-depend/README.md — the only real API documentation. Read it before writing a second field; method names and the options-closure signature are the thing you'll get wrong.
  2. vendor/orlyapps/nova-belongsto-depend/src/ — the PHP field class and the route controller that resolves options. It's small; read all of it in ten minutes. This is the code you can actually patch.
  3. vendor/orlyapps/nova-belongsto-depend/dist/js/ — the compiled Vue field. Opaque. Treat as read-only; there is no build chain shipped.

First use case. Take one cascading pair you already have as two plain BelongsTo fields — country → state is the canonical one — and convert only the child on a throwaway branch, on one resource:

use Orlyapps\NovaBelongsToDepend\NovaBelongsToDepend;

public function fields(NovaRequest $request)
{
    return [
        BelongsTo::make('Country', 'country', Country::class)
            ->searchable(),

        NovaBelongsToDepend::make('State', 'state')
            ->options(fn () => State::query()
                ->select('id', 'name')
                ->orderBy('name')
                ->get()
                ->pluck('name', 'id'))
            ->dependsOn('country'),
    ];
}

(Verify the exact method names and the closure's parameters against the vendor README — the package is unmaintained and its docs are the source of truth, not this snippet.)

Spike checklist before you commit to it. Create, edit, validation-error redisplay, searchable-child, empty parent, nullable parent then set-then-cleared. Record the exact Nova major/minor where it mounts, and pin both orlyapps/nova-belongsto-depend and laravel/nova in composer.lock so a Nova upgrade can't silently drag the field into an unsupported runtime.

Implementation Patterns

Parent stays plain, only the child is dependent. Don't convert the whole chain to the package's field. Keeping the root as a normal BelongsTo gives you a working baseline to compare against when the dependent field misbehaves, and a one-line rollback.

Three-level chains (country → state → city). Each level depends on the level immediately above it, and each options closure must filter by the immediate parent only. The common bug is filtering level three by the root value because that's the id you have handiest — it works in the happy path and breaks the moment someone is editing a record whose chain was built differently.

Keep the options closure a constrained query.

->options(fn (NovaRequest $request) => City::query()
    ->select('id', 'name')
    ->when($request->state, fn ($q, $state) => $q->where('state_id', $state))
    ->orderBy('name')
    ->pluck('name', 'id'))

Select only the columns you pluck, order deterministically, and never Model::all(). If the lookup table is large, ->limit() + ->searchable() on the child rather than a full list.

Scope it to forms. These fields have no meaning in index/detail contexts. ->onlyOnForms() (or ->hideFromIndex()) keeps the extra query and the extra JS off list screens, where it's pure overhead.

Migrate one field at a time. Each replacement is independently reversible: swap the dependent field back to BelongsTo and the column is unchanged, because both bind to the same foreign key. Do this in the same PR as the resource change, not as a follow-up sweep.

Run the build-vs-buy spike in parallel. While you're validating the package, spend the same afternoon attempting Nova's native dependsOn() plus a relatable() closure. If it reaches parity in ~100 lines you own, take the in-house field and close the ticket — the package's value is convenience, and convenience doesn't justify an unmaintained dependency.

Test with seeded fixtures, not production data. A seeder with two countries, two states each, and a null-country record lets you exercise every branch (change parent, clear parent, edit existing) in about five minutes of manual clicks. Do it after every Nova bump.

Gotchas and Tips

The headline failure mode is silent. After a Nova upgrade the field can render perfectly, look correct, and simply never refresh its options — no console error, no exception. Operators then save invalid parent/child combinations. Add an explicit smoke test on the dependent form to your Nova upgrade checklist, and don't rely on "the admin still loads" as a pass.

Last release was June 2022, right at the Nova 3 → 4 (Vue 2 → Vue 3) boundary. Nova 4 and 5 support is unverified — treat it as broken until a spike proves otherwise on your Nova version. Pin laravel/nova explicitly so a minor bump doesn't quietly break it.

The frontend is compiled and unbuildable. You can read and patch the PHP side; you cannot reasonably regenerate dist/js. If the JS side needs a fix, your options are a fork with a rebuilt asset or an in-house field. Fork before broadening adoption, not during an incident.

Edit forms resolve differently than create forms. Parent and child values hydrate in a different order, and the classic symptom is a stale or empty child dropdown when opening an existing record. Always test edit separately from create; a passing create test proves nothing about edit.

Clearing the parent can leave a stale child id in the payload. Click through it: set country → set state → clear country → save. If the child id survives, you have a data-integrity bug in the exact workflow the package was bought to fix.

Client-side filtering is not validation. The dropdown narrows options; nothing on the server rejects a mismatched pair posted by a crafted request. If data quality is the justification, add a Rule::exists() constrained by the parent (or a form-request/observer check) — the field alone doesn't give you integrity.

Confirm the option lookup is server-side and constrained. If the field fetches everything and filters in JS, large lookup tables become a latency and correctness problem, and the option list can silently widen.

Authorization isn't free. Nova's relatable() respects policies; a raw options() query does not. Filter the closure by what the current user may see, or you've created an information leak in an admin form.

Searchable-child interactions need explicit testing. Type into the child, then change the parent, then type again. Search that runs server-side can ignore the dependent filter and surface out-of-scope results.

Debugging: watch the network tab. When options don't refresh, the vendor route's response is the fastest signal — absent request means the JS side, wrong/empty body means your query. Cross-check composer.lock for the Nova version before you debug anything else.

Write the ownership down. Add a code comment at the field definition naming the package as unmaintained, and record one named owner plus a documented fallback (fork under your org, or swap to the in-house field). This is a sub-500-line field with zero dependents and a single maintainer — the risk isn't severity, it's that nobody notices for two years. Don't let it gate a Nova upgrade.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource