Fields

Overview

Nova ships with a variety of field types; however, sometimes you may need a field type that isn't provided out of the box. For this reason, Nova allows you to build custom fields. Custom fields consist of three Vue components that determine how the field is displayed in various contexts.

Defining Fields

Custom fields may be generated using the nova:field Artisan command. By default, all new fields will be placed in the nova-components directory of your application. When generating a field using the nova:field command, the field name you pass to the command should follow the Composer vendor/package format. So, if we were building a color-picker field, we might run the following command:

php artisan nova:field acme/color-picker

When generating a field, Nova will prompt you to install the field's NPM dependencies, compile its assets, and update your application's composer.json file. All custom fields are registered with your application as a Composer "path" repository.

Nova fields include all of the scaffolding necessary to build your field. Each field even contains its own composer.json file and is ready to be shared with the world on GitHub or the source control provider of your choice.

Registering Fields

Nova fields may be registered in your resource's fields method. This method returns an array of fields available to the resource. To register your field, add your field to the array of fields returned by this method:

use Acme\ColorPicker\ColorPicker;

/**
 * Get the fields displayed by the resource.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return array
 */
public function fields(Request $request)
{
    return [
        ID::make('ID', 'id')->sortable(),

        ColorPicker::make('Color'),
    ];
}

Field Options

Often, you will need to allow the consumer's of your field to customize run-time configuration options on the field. You may do this by exposing methods on your field class. These methods may call the field's underlying withMeta method to add information to the field's metadata, which will be available within your field's Vue components. The withMeta method accepts an array of key / value options:

<?php

namespace Acme\ColorPicker;

use Laravel\Nova\Fields\Field;

class ColorPicker extends Field
{
    /**
     * The field's component.
     *
     * @var string
     */
    public $component = 'color-picker';

    /**
     * Set the hues that may be selected by the color picker.
     *
     * @param  array  $hues
     * @return $this
     */
    public function hues(array $hues)
    {
        return $this->withMeta(['hues' => $hues]);
    }
}

Building Fields

Each field generated by Nova includes its own service provider and "field" class. Using the color-picker field as an example, the field class will be located at src/ColorPicker.php.

The field's service provider is also located within the src directory of the field, and is registered in your field's composer.json file so that it will be auto-loaded by the Laravel framework.

Index Fields

When Nova generates your field, it creates a resources/js/components/IndexField.vue Vue component. This component contains the template and logic for your field when it is displayed on a resource index screen. By default, this component simply displays the field's value in a simple <span> element; however, you are free to modify this field component as needed.

Detail Fields

When creating fields, Nova also creates a resources/js/components/DetailField.vue Vue component. This component contains the template and logic for your field when it is displayed on a resource detail screen. By default, this template contains the necessary mark-up needed to display your field's value. However, you are free to adjust this template as required by your application.

Form Fields

Finally, Nova creates a resources/js/components/FormField.vue Vue component. This component contains the template and logic for your field when it is displayed on a creation or update form. By default, this template contains a simple input control to modify your field's underlying value; however, you are free to customize this template. For example, we may update the template to display a color-picker control:

<template>
    <default-field :field="field">
        <template slot="field">
            <input :id="field.name" type="color"
                class="w-full form-control form-input form-input-bordered"
                :class="errorClasses"
                :placeholder="field.name"
                v-model="value"
            />

            <p v-if="hasError" class="my-2 text-danger">
                {{ firstError }}
            </p>
        </template>
    </default-field>
</template>

Setting The Form Value

Before creating or updating a resource, Nova asks each field on the form to "fill" the outgoing FormData object with key / value pairs. Each field may add as many elements to the FormData as needed. This may done in your FormField.vue file's fill method:

/**
 * Fill the given FormData object with the field's internal value.
 */
fill(formData) {
  formData.append(this.field.attribute, this.value || '')
}

Hydrating The Model

By default, when saving a model, your field class will simply copy the incoming form field value into the field's associated model attribute. However, you may customize how your field hydrates the resource model. To accomplish this, override the fillAttributeFromRequest method on your field class:

<?php

namespace Otwell\ColorPicker;

use Laravel\Nova\Fields\Field;

class ColorPicker extends Field
{
    /**
     * The field's component.
     *
     * @var string
     */
    public $component = 'color-picker';

    /**
     * Hydrate the given attribute on the model based on the incoming request.
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @param  string  $requestAttribute
     * @param  object  $model
     * @param  string  $attribute
     * @return void
     */
    protected function fillAttributeFromRequest(NovaRequest $request,
                                                $requestAttribute,
                                                $model,
                                                $attribute)
    {
        if ($request->exists($requestAttribute)) {
            $model->{$attribute} = $request[$requestAttribute];
        }
    }
}

This method receives several arguments. Of course, it receives the incoming HTTP request and the model that is being updated. The method also receives the $requestAttribute, which is the name of the incoming form field on the HTTP request. Additionally, it receives the $attribute, which is the name of the model attribute the field's value should be placed in.

Assets

When Nova generates your field, resources/js and resources/sass directories are generated for you. These directories contain your field's JavaScript and Sass stylesheets.

Field Properties

Your field's Vue components receive a field Vue prop. The field property provides access to any field options that may be available:

const hues = this.field.hues;

Registering Assets

Your Nova field's service provider registers your field's compiled assets so that they will be available to the Nova front-end:

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Nova::serving(function (ServingNova $event) {
        Nova::script('stripe-inspector', __DIR__.'/../dist/js/field.js');
        Nova::style('stripe-inspector', __DIR__.'/../dist/css/field.css');
    });
}

JavaScript Bootstrap & Routing

Your components are bootstrapped and registered in the resources/js/field.js file. You are free to modify this file or register additional components here as needed.

Compiling Assets

Your Nova field contains a webpack.mix.js file, which is generated when Nova creates your field. You may build your field using the NPM dev and prod commands:

// Compile your assets for local development...
npm run dev

// Compile and minify your assets...
npm run prod

In addition, you may run the NPM watch command to auto-compile your assets when they are changed:

npm run watch