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

China Distpicker Laravel Package

laravel-admin-ext/china-distpicker

Laravel Admin extension that adds a cascading China province, city, and district picker to forms. It provides an easy-to-use regional selector for Chinese addresses, with built-in province, city, and district data and seamless integration into laravel-admin.

View on GitHub
Deep Wiki
Context7

Getting Started

china-distpicker adds a three-column cascading region selector (省 / 市 / 区) to laravel-admin forms. It is a thin wrapper: the PHP side gives you a distpicker form field bound to three model columns, and the front end loads the distpicker JS bundle that filters city options by province and district by city. There is no server-side region logic at all — the package's job is the widget and the dataset.

Prerequisites and install:

# requires encore/laravel-admin 1.x already installed and bootstrapped
composer require laravel-admin-ext/china-distpicker

# publish the JS asset/data bundle if the release ships a publishable tag
php artisan vendor:publish --tag=laravel-admin-china-distpicker

php artisan admin:import ...   # not needed; no menu item

Then clear caches (php artisan cache:clear, php artisan view:clear) and hard-refresh the browser.

Where to look first, in order:

  1. README.md — the only real documentation; it is short, so read it fully.
  2. src/Distpicker.php — the field class. This tells you the exact method signature, whether it accepts a label, and whether it supports default().
  3. resources/views/ — the Blade template. This reveals the DOM ids/classes and which asset path is expected, which is what you debug when the selects render empty.
  4. The published asset under public/vendor/laravel-admin-ext/china-distpicker/ (path may vary by version).

First use case: an orders or shops table with province, city, district columns (all string, nullable or not, per your validation):

// app/Admin/Controllers/ShopController.php
protected function form()
{
    $form = new Form(new Shop());

    $form->text('name', '名称');
    $form->distpicker(['province', 'city', 'district'], '所在地区');
    $form->text('address', '详细地址');

    return $form;
}

That's the whole happy path: one line replaces three separate select fields and the dependent-option wiring you would otherwise write by hand.

Implementation Patterns

Keep the array order fixed. The field maps positionally to [province, city, district]. Renaming or reordering the array without renaming the columns is the most common cause of "values saved to the wrong column."

Edit forms work for free, if you name things consistently. The field hydrates from the model's attributes, so province/city/district in the array must match real DB columns and the model's $fillable. Any mismatch and the update silently drops the value.

Validation belongs outside the field. Treat the widget as UI-only and validate on the request:

// FormRequest or controller
'province' => 'required|string|max:64',
'city'     => 'required|string|max:64',
'district' => 'required|string|max:64',

If you want a real integrity check ("南山区 must belong to 深圳市"), write a custom rule against the same dataset the JS uses. The package does not verify that the posted trio is a valid cascade, and a hand-crafted POST can submit any three strings.

Compose with the rest of the address. Regional cascade plus a free-text detail field is the standard pattern; put the detail field immediately after the distpicker so the visual order matches the stored order.

Reuse across resources. Wrap the three lines in a small trait or helper (AddressFormFields::attach($form)) rather than copy-pasting column names into every controller — you will change naming or validation once and want it in one place.

Conditional and read-only variants. Standard laravel-admin field methods (->rules(), ->help(), ->when(), ->hide(), ->readonly()) apply to the field, but verify each on your version — see the gotcha on rules() below.

Display side. $show->field('province') prints the raw stored string. If you store codes rather than names, add ->using(fn ($v) => RegionMap::name($v)) so grids and detail pages stay readable.

Imports and APIs. Because storage is just three strings, seeding/importing rows needs no special handling — only vocabulary consistency (names vs. codes, 省 vs. 广东省). Normalize before insert or your grids will mix formats.

If you are not on laravel-admin 1.x: do not try to install this. On OpenAdmin, Filament or Nova, port the Blade template and register it as a custom field, or use a generic two-to-three-level cascading select component. The JS library at the core is replaceable; the PHP wrapper is ~50 lines.

Gotchas and Tips

  • It is a 2021 package for a maintenance-mode framework. Last release October 2021, zero dependents. Expect Composer conflicts on Laravel 9/10 or PHP 8.1+. Fork it, loosen composer.json constraints, and re-test rather than fighting --ignore-platform-reqs in CI.
  • Empty selects almost always mean unpublishable assets. If the three boxes render but never cascade, open the browser console and confirm the distpicker JS bundle loaded from public/vendor/.... Re-publish with --force, then hard-refresh.
  • rules() on multi-column fields is the sharp edge. In laravel-admin, a field that spans multiple columns typically applies its rules to one column name only. Do not assume ->rules('required') validates all three — put the rules in your FormRequest/controller and add a test that posts a blank province.
  • The first option may overwrite existing data. Cascading widgets initialize to the first available province. If an existing row has a null or stale district, simply opening and saving the edit form can rewrite the region. Guard with a saving callback that skips the trio when unchanged, or make the columns part of a required contract.
  • Names vs. codes is a decision you cannot defer. The stock dataset yields display names (广东省 / 深圳市 / 南山区). Logistics, mapping and tax APIs usually want GB/T codes. Pick one storage format on day one; converting thousands of rows later is painful.
  • The bundled dataset is frozen at release time. Administrative changes after ~2021 (new districts, merged counties) will be missing. If accuracy matters, serve your own data file and point the widget at it rather than editing vendor assets.
  • Two distpickers on one form can collide if the Blade template hardcodes element ids. Check resources/views/ before assuming it is safe; overriding the view via ->view('admin.fields.distpicker') with unique ids is the fix.
  • Localization. Labels, placeholders and the dataset are Chinese. On an English admin panel, pass your own label as the second argument and check whether the placeholder strings are translatable or hardcoded in Blade.
  • Debugging checklist: inspect the rendered HTML for the three select names, confirm the JS asset 200s in the network tab, confirm the model's $fillable includes all three columns, then check the DB write in ->saved().
  • Extension points: subclass the field class, override the Blade view, or swap the JS for a maintained alternative (china-area-data, element-china-area-data). All three are low-effort compared to replacing the whole admin panel.
  • Testing: feature tests just POST the three strings — the cascade is client-side, so the only backend behaviour worth asserting is presence, format and consistency validation.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings