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 Prepopulate Searchable Laravel Package

alexbowers/nova-prepopulate-searchable

A Laravel Nova package that lets you prepopulate searchable relationship fields from URL query parameters, making it easier to create records with preselected BelongsTo values from links or filtered lists.

View on GitHub
Deep Wiki
Context7

Getting Started

Requirements: Laravel with Nova installed (package last shipped Feb 2022, so assume Nova 3.x first, Nova 4.x with verification). PHP 7.4/8.0-era code.

Install:

composer require alexbowers/nova-prepopulate-searchable

No publish step or config file is documented; the package ships a field class plus its compiled Nova JS component. Confirm the README at your pinned tag for the exact class namespace and method names before wiring it into a resource.

Where to look first:

  1. vendor/alexbowers/nova-prepopulate-searchable/README.md — the API surface is small, but method names are version-sensitive.
  2. src/ — the field class (extends Nova's BelongsTo) and any service provider.
  3. dist/js/ — the compiled Vue component; this is what actually replaces the stock searchable BelongsTo UI.

First use case — nested / scoped create forms. The canonical scenario is a "create child from parent" screen: you already know the parent record (route model binding, query string, or tenant context), but a plain BelongsTo::make(...)->searchable() renders an empty search box because the option list is fetched by AJAX only when the user types. Prepopulating seeds the option list so the known record displays its title() immediately.

use Alexbowers\NovaPrepopulateSearchable\PrepopulateSearchable;

public function fields(Request $request)
{
    return [
        // exact method name per README; conceptually: provide the initial option(s)
        PrepopulateSearchable::make('Author', 'author_id')
            ->searchable()
            ->prepopulate(fn () => User::whereKey($request->query('author_id'))->pluck('name', 'id')),
    ];
}

If that single use case is all you need, this package is a reasonable shortcut; if you need more, see the migration note in Gotchas.

Implementation Patterns

1. Fixed record prepopulation (nested resource create). Pass the already-known model or a single-entry map. The user sees "Jane Doe" without searching, and the hidden author_id is set.

PrepopulateSearchable::make('Post', 'post_id')
    ->searchable()
    ->prepopulate(fn () => Post::whereKey(request()->route('post'))->pluck('title', 'id'))
    ->readonly(), // if the relation is fixed by the route

2. Closure driven by request context. Because the value is resolved at field-serialization time (per request), closures can read query strings, route params, or the authenticated user. Always scope:

->prepopulate(fn () => User::query()
    ->where('tenant_id', request()->user()->tenant_id)
    ->whereKey(request('author_id'))
    ->pluck('name', 'id'))

3. Tenant / ownership scoping as a habit. Prepopulation bypasses the normal search endpoint, so your relatableQueryUsing() rules are not applied to the seeded options. Mirror the same constraints in the closure, or you create a display-level leak (the label resolves for a record the user shouldn't see).

4. Combine with searchable() and relatableQueryUsing(). Keep the field searchable so users can change the selection; only the initial options come from the package.

PrepopulateSearchable::make('Author', 'author_id')
    ->searchable()
    ->relatableQueryUsing(fn ($request, $query) => $query->where('tenant_id', $request->user()->tenant_id))
    ->prepopulate(fn () => /* same scope */);

5. Shared builder for index/show vs. forms. Nova serializes fields for both the resource index and the detail form; the prepopulation payload is usually wasted on index. Guard the closure with cheap whereKey lookups rather than loading full lists, and prefer pluck('name','id') over get().

6. Update forms. On edit, Nova already knows the current value and resolves its label. Prepopulation matters mainly for create and for dependent/dynamic forms — verify the field still behaves on update in your Nova version, since older components sometimes overwrite the resolved value.

7. Display-only prepopulation. For immutable relations (a comment always belongs to its post), pair prepopulation with readonly()/disabled() so the UI shows the label but the user cannot re-search and swap parents.

Gotchas and Tips

  • Archived package. No fixes for Nova 4/5, no JS rebuilds, no security patches. Pin the exact version and smoke-test the search field on both create and update after any Nova or Laravel upgrade. If it breaks, fork it into app/Nova/Fields or packages/ rather than waiting for upstream.
  • Nova major-version compatibility is the primary risk. The compiled Vue component targets the Nova build current at release (early 2022). Field JSON shapes changed between Nova 3 and 4 (field.meta, component registration, field.choices/options handling), so a silent no-op render is the most likely failure mode — not a hard error.
  • Verify method names against the tagged README. The public API is a thin wrapper, and method names were not stable across the package's short life. Don't assume prepopulate()/prepopulateUsing() from memory; read src/ before writing resource code.
  • Scoping bypass (biggest correctness trap). Prepopulated options are injected server-side, outside Nova's search authorization flow. Duplicate every tenant/ownership constraint you rely on in relatableQueryUsing().
  • Closure cost. The closure runs on every serialization of the form (and possibly index). Use whereKey + pluck, never Model::all(), and avoid loading relationships you don't display.
  • Key/type matching. Nova expects a [id => label] map and matches against the field's stored value, often as a string. Cast keys (->pluck('name','id') returns ints from many drivers; use ->mapWithKeys or string-cast if the component fails to select the initial value).
  • title() mismatch. The label shown by prepopulation should come from the same attribute the related resource uses for title()/$title, otherwise the displayed name changes after the first search.
  • Dependent fields (dependsOn). Prepopulation is computed at serialization time; it will not react when a parent field changes. If the relation depends on another field's value, you need custom JS or a different approach — this package cannot do it.
  • Nullable relations. Passing an empty collection/null should degrade to a normal empty searchable field; test that it doesn't render a stray blank option or throw.
  • Debugging. Open the browser devtools Network tab and inspect the /nova-api/... field payload: confirm the prepopulated entries actually appear in the field's options/choices meta. If they're present but not rendered, the issue is the Vue component vs. Nova version; if absent, it's your closure or method call.
  • Extension points / escape hatch. Subclass the field and override jsonSerialize()/resolve() to inject options yourself, or sidestep the package entirely:
    • use a plain Select with ->options(...) when the set is small and static;
    • use BelongsTo::make(...)->searchable()->default($id) plus a small custom field if you only need the value preselected;
    • for one-off screens, a non-searchable Select populated from the same scoped query is often simpler and survives Nova upgrades.

Bottom line: good fit for the narrow "known related record should display immediately in a searchable BelongsTo" problem, with a short implementation. Treat it as archived code you own: pin, scope all closures, and plan a fork or an inline replacement before your next Nova major 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.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core