Craftable

Form

Admin UI comes with predefined Vue ajax form mixin, which you can use and customize in your own Vue form. These mixin is capable of handle all typical form usecases such as ajax form submit, error handling etc. You can also easily add Media upload functionality.

Example of typical Vue form component

import AppForm from '../app-components/Form/AppForm';

Vue.component('post-form', {
    mixins: [AppForm],
    data: function() {
        return {
            form: {
                //define all your form inputs here, 
                //this exact data structure will be sent to your backend

                title:  this.getLocalizedFormDefaults(),
                perex:  this.getLocalizedFormDefaults(),
                published_at:  '' ,
                is_published:  false ,
            },
        }
    }
});

You'll also need number of blade form components, but don't worry, if you're using our package brackets/admin-generator, all these files will be generated for you.

Example of typical create form

@extends('brackets/admin-ui::admin.layout.default')
@section('title', trans('admin.post.actions.create'))

@section('body')
    <div class="container-xl">
        <div class="card">
            <post-form
                :action="'{{ url('admin/post/store') }}'"
                :locales="{{ json_encode($locales) }}"
                :send-empty-locales="false"
                inline-template>

                <form class="form-horizontal form-create" method="post" @submit.prevent="onSubmit" :action="this.action" novalidate>
                    <div class="card-header">
                        <i class="fa fa-plus"></i> {{ trans('admin.post.actions.create') }}
                    </div>

                    <div class="card-block">
                        @include('admin.post.components.form-elements')
                    </div>

                    <div class="card-footer">
                        <button type="submit" class="btn btn-primary">
                            <i class="fa" :class="submiting ? 'fa-spinner' : 'fa-download'"></i>
                            {{ trans('brackets/admin-ui::admin.btn.save') }}
                        </button>
                    </div>
                </form>
            </post-form>
        </div>
    </div>
@endsection

Example of typical edit form

@extends('brackets/admin-ui::admin.layout.default')
@section('title', trans('admin.post.actions.edit', ['name' => $post->title]))
@section('body')

    <div class="container-xl">
        <div class="card">
            <post-form
                :action="'{{ route('admin/post/update', ['post' => $post]) }}'"
                :data="{{ $post->toJsonAllLocales() }}"
                :locales="{{ json_encode($locales) }}"
                :send-empty-locales="false"
                inline-template>

                <form class="form-horizontal form-edit" method="post" @submit.prevent="onSubmit" :action="this.action" novalidate>
                    <div class="card-header">
                        <i class="fa fa-pencil"></i> {{ trans('admin.post.actions.edit', ['name' => $post->title]) }}
                    </div>

                    <div class="card-block">
                        @include('admin.post.components.form-elements')
                    </div>

                    <div class="card-footer">
                        <button type="submit" class="btn btn-primary" :disabled="submiting">
                            <i class="fa" :class="submiting ? 'fa-spinner' : 'fa-download'"></i>
                            {{ trans('brackets/admin-ui::admin.btn.save') }}
                        </button>
                    </div>
                </form>
        </post-form>
    </div>
</div>
@endsection

Example of form-elements component

<div class="row form-inline" style="padding-bottom: 10px;" v-cloak>

    <div :class="{'col-xl-10 col-md-11 text-right': !isFormLocalized, 'col text-center': isFormLocalized }">
        <small>{{ trans('brackets/admin-ui::admin.forms.currently_editing_translation') }}<span v-if="!isFormLocalized && otherLocales.length > 1"> {{ trans('brackets/admin-ui::admin.forms.more_can_be_managed') }}</span> <span v-if="!isFormLocalized"> | <a href="#" @click.prevent="showLocalization">{{ trans('brackets/admin-ui::admin.forms.manage_translations') }}</a></span></small>
        <i class="localization-error" v-if="!isFormLocalized && showLocalizedValidationError"></i>
    </div>
    <div class="col text-center" v-if="isFormLocalized" v-cloak>
        <small>{{ trans('brackets/admin-ui::admin.forms.choose_translation_to_edit') }}
            <select class="form-control" v-model="currentLocale">
                <option v-for="locale in otherLocales" :value="locale">@{{ locale.toUpperCase() }}</option>
            </select>
            <i class="localization-error" v-if="isFormLocalized && showLocalizedValidationError"></i>
            |
            <a href="#" @click.prevent="hideLocalization">{{ trans('brackets/admin-ui::admin.forms.hide') }}</a>
        </small>
    </div>
</div>

<div class="row">
    @foreach($locales as $locale)
        <div class="col"@if(!$loop->first) v-show="isFormLocalized && currentLocale == '{{ $locale }}'" v-cloak @endif>
            <div class="form-group row" :class="{'has-danger': errors.has('title_{{ $locale }}'), 'has-success': this.fields.title_{{ $locale }} && this.fields.title_{{ $locale }}.valid }">
                <label for="title_{{ $locale }}" class="col-md-2 col-form-label text-md-right">{{ trans('admin.movie.columns.title') }}</label>
                <div class="col-md-9" :class="{'col-xl-8': !isFormLocalized }">
                    <input type="text" v-model="form.title.{{ $locale }}" v-validate="'required'" class="form-control" :class="{'form-control-danger': errors.has('title_{{ $locale }}'), 'form-control-success': this.fields.title_{{ $locale }} && this.fields.title_{{ $locale }}.valid }" id="title_{{ $locale }}" name="title_{{ $locale }}" placeholder="{{ trans('admin.movie.columns.title') }}">
                    <div v-if="errors.has('title_{{ $locale }}')" class="form-control-feedback form-text" v-cloak>{{'{{'}} errors.first('title_{{ $locale }}') }}</div>
                </div>
            </div>
        </div>
    @endforeach
</div>

<div class="row">
    @foreach($locales as $locale)
        <div class="col"@if(!$loop->first) v-show="isFormLocalized && currentLocale == '{{ $locale }}'" v-cloak @endif>
            <div class="form-group row" :class="{'has-danger': errors.has('{{ $locale }}_perex'), 'has-success': this.fields.{{ $locale }}_perex && this.fields.{{ $locale }}_perex.valid }">
                <label for="{{ $locale }}_perex" class="col-md-2 col-form-label text-md-right">{{ trans('admin.movie.columns.perex') }}</label>
                <div class="col-md-9" :class="{'col-xl-8': !isFormLocalized }">
                    <div>
                        <textarea v-model="form.perex.{{ $locale }}" v-validate="'required'" class="hidden-xs-up" id="{{ $locale }}_perex" name="{{ $locale }}_perex"></textarea>
                        <quill-editor v-model="form.perex.{{ $locale }}" :options="wysiwygConfig" />
                    </div>
                    <div v-if="errors.has('{{ $locale }}_perex')" class="form-control-feedback form-text" v-cloak>{{'{{'}} errors.first('{{ $locale }}_perex') }}</div>
                </div>
            </div>
        </div>
    @endforeach
</div>

<div class="form-group row" :class="{'has-danger': errors.has('published_at'), 'has-success': this.fields.published_at && this.fields.published_at.valid }">
    <label for="published_at" class="col-form-label text-md-right" :class="isFormLocalized ? 'col-md-4' : 'col-sm-2'">{{ trans('admin.movie.columns.published_at') }}</label>
    <div :class="isFormLocalized ? 'col-md-4' : 'col-md-9 col-xl-8'">
        <div class="input-group input-group--custom">
            <div class="input-group-addon"><i class="fa fa-clock-o"></i></div>
            <datetime v-model="form.published_at" :config="datetimePickerConfig" v-validate="'date_format:YYYY-MM-DD kk:mm:ss'" class="flatpickr" :class="{'form-control-danger': errors.has('published_at'), 'form-control-success': this.fields.published_at && this.fields.published_at.valid}" id="published_at" name="published_at" placeholder="{{ trans('brackets/admin-ui::admin.forms.select_date_and_time') }}"></datetime>
        </div>
        <div v-if="errors.has('published_at')" class="form-control-feedback form-text" v-cloak>@{{ errors.first('published_at') }}</div>
    </div>
</div>

<div class="form-check row" :class="{'has-danger': errors.has('is_published'), 'has-success': this.fields.is_published && this.fields.is_published.valid }">
    <div class="ml-md-auto" :class="isFormLocalized ? 'col-md-8' : 'col-md-10'">
            <input class="form-check-input" id="checkbox" type="checkbox" v-model="form.is_published" v-validate="'required'" data-vv-name="is_published"  name="is_published_fake_element">
            <label class="form-check-label" for="checkbox">
                {{ trans('admin.movie.columns.is_published') }}
            </label>
            <input type="hidden" name="is_published" :value="form.is_published">
        <div v-if="errors.has('is_published')" class="form-control-feedback form-text" v-cloak>@{{ errors.first('is_published') }}</div>
    </div>
</div>