Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/bayareawebpro/laravel-multistep-forms
Responsable Multistep Form Builder for Laravel
https://github.com/bayareawebpro/laravel-multistep-forms
builder forms laravel laravel-multistep-forms multistep multistep-forms sessions validation
Last synced: 5 days ago
JSON representation
Responsable Multistep Form Builder for Laravel
- Host: GitHub
- URL: https://github.com/bayareawebpro/laravel-multistep-forms
- Owner: bayareawebpro
- License: mit
- Created: 2020-04-13T22:18:23.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2023-12-25T03:57:50.000Z (about 1 year ago)
- Last Synced: 2024-04-25T16:20:38.449Z (9 months ago)
- Topics: builder, forms, laravel, laravel-multistep-forms, multistep, multistep-forms, sessions, validation
- Language: PHP
- Size: 88.9 KB
- Stars: 88
- Watchers: 8
- Forks: 11
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Laravel MultiStep Forms
![](https://github.com/bayareawebpro/laravel-multistep-forms/workflows/ci/badge.svg)
![](https://codecov.io/gh/bayareawebpro/laravel-multistep-forms/branch/master/graph/badge.svg)
![](https://img.shields.io/github/v/release/bayareawebpro/laravel-multistep-forms.svg)
![](https://img.shields.io/packagist/dt/bayareawebpro/laravel-multistep-forms.svg)
![](https://img.shields.io/badge/License-MIT-success.svg)> https://packagist.org/packages/bayareawebpro/laravel-multistep-forms
Multistep Form Builder is a "[responsable](https://laravel-news.com/laravel-5-5-responsable)" class that can be returned from controllers.
* Specify a view to use Blade or go headless with JSON for use with Javascript frameworks.
* Configure the rules, messages and supporting data for each step with simple arrays.
* Submit to the same route multiple times to merge each validated request into a namespaced session key.
* Hook into each step **before** or **after** validation to interact with the form or return a response.## Installation
```shell script
composer require bayareawebpro/laravel-multistep-forms
```### Example Usage
```php
'MultiStep Form'
])// Namespace the session data.
->namespaced('my-session-key')// Allow backwards navigation via get request. ?form_step=x
->canNavigateBack(true)// Tap invokable Class __invoke(Form $form)
->tap(new InvokableClass)// Before x step validation...
->beforeStep(1, function (MultiStepForm $form) {
// Maybe return early or redirect?
})
// Before all step validation...
->beforeStep('*', function (MultiStepForm $form) {
// Maybe return early or redirect?
})// Validate Step 1
->addStep(1, [
'rules' => ['name' => 'required'],
'messages' => ['name.required' => 'Your name is required.'],
])// Validate Step 2
->addStep(2, [
'rules' => ['role' => 'required|string'],
'data' => ['roles' => fn()=>Role::forSelection()] // Lazy Loaded Closure
])// Add non-validated step...
->addStep(3,[
'data' => ['message' => "Great Job, Your Done!"]
])// After step validation...
->onStep(3, function (MultiStepForm $form) {
// Specific step, logic if needed.
})
->onStep('*', function (MultiStepForm $form) {
// All steps, logic if needed.
})
// Modify data before saved to session after each step.
->beforeSave(function(array $data) {
// Transform non-serializable objects to paths, array data etc...
return $data;
})
// Modify data before saved to session after each step.
->onComplete(function(MultiStepForm $form) {
// Final submission logic.
})
;
```---
### Make New Instance
Make a new instance of the builder class with optional view and data array. You
should always set the `namespace` for the form session to avoid conflicts with
other parts of your application that use the session store.* `GET` requests will load the form state and data for the saved current step or fallback to step 1.
* `POST`,`PUT`,`PATCH` etc... will validate and process the request for any step and proceed to the next configured step.
* `DELETE` will reset the session state and redirect back (blade), or return a `JsonResponse`.
* Backwards navigation (via get param) can be enabled via the `canNavigateBack` method.```php
'Setup your account'
]);$form->namespaced('onboarding');
$form->canNavigateBack(true);
```---
### Configure Steps
Define the rules, messages and data for the step. Data will be merged
with any view data defined in the `make` method and be included in the `JsonResponse`.** Use a `Closure` to lazy load data per-key.
**Use an array**:
```php
$form->addStep(2, [
'rules' => [
'role' => 'required|string'
],
'messages' => [
'role.required' => 'Your name is required.'
],
'data' => [
'roles' => fn() => Role::query()...,
],
])
```**Or use an invokable class** (recommended)
```php
use BayAreaWebPro\MultiStepForms\MultiStepForm;class ProfileStep
{
public function __construct(private int $step)
{
//
}
public function __invoke(MultiStepForm $form)
{
$form->addStep($this->step, [
'rules' => [
'name' => 'required|string'
],
'messages' => [
'name.required' => 'Your name is required.'
],
'data' => [
'placeholders' => [
'name' => 'Enter your name.'
]
],
]);
}
}
``````php
$form->tap(new ProfileStep(1));
```---
### BeforeStep / OnStep Hooks
Define a callback to fired **before** a step has been validated. Step Number or * for all.
- Use a step integer, or asterisk (*) for all steps.
- You can return a response from these hooks.```php
$form->beforeStep('*', function(MultiStepForm $form){
//
});
$form->onStep('*', function(MultiStepForm $form){
//
});
$form->onComplete(function(MultiStepForm $form){
//
});
```### Handle UploadedFiles
Specify a callback used to transform UploadedFiles into paths.
```php
use Illuminate\Http\UploadedFile;$form->beforeSave(function(array $data){
if($data['avatar'] instanceof UploadedFile){
$data['avatar'] = $data['avatar']->store('avatars');
}
return $data;
});
```### Reset / Clear Form
- Ajax: Submit a DELETE request to the form route.
- Blade: Use an additional submit button that passes a boolean (truthy) value.```
Reset
```### JSON Response Schema
The response returned will have two properties:
```json
{
"form": {
"form_step": 1
},
"data": {}
}
```### Public Helper Methods
#### stepConfig
Get the current step configuration (default), or pass an integer for a specific step:
```php
$form->stepConfig(2): Collection
```#### getValue
Get a field value (session / old input) or fallback:```php
$form->getValue('name', 'John Doe'): mixed
```#### setValue
Set a field value and store in the session:
```php
$form->setValue('name', 'Jane Doe'): MultiStepForm
```#### save
Merge and save key/values array directly to the session (does not fire `beforeSaveCallback`):```php
$form->save(['name' => 'Jane Doe']): MultiStepForm
```#### reset
Reset the form state to defaults passing an optional array of data to seed.
```php
$form->reset(['name' => 'Jane Doe']): MultiStepForm
```#### withData
Add additional non-form data to all views and responses:```php
$form->withData(['date' => now()->toDateString()]);
```#### currentStep
Get the current saved step number:```php
$form->currentStep(): int
```#### requestedStep
Get the incoming client-requested step number:```php
$form->requestedStep(): int
```#### isStep
Is the current step the provided step:```php
$form->isStep(3): bool
```#### prevStepUrl
Get the previous step url.```php
$form->prevStepUrl(): string|null
```#### lastStep
Get the last step number:```php
$form->lastStep(): int
```#### isLastStep
Is the current step the last step:```php
$form->isLastStep(): bool
```#### isPast,isActive,isFuture
```php
// Boolean Usage
$form->isPast(2): bool
$form->isActive(2): bool
$form->isFuture(2): bool// Usage as HTML Class Helpers
$form->isPast(2, 'truthy-class', 'falsy-class'): string
$form->isActive(2, 'truthy-class', 'falsy-class'): string
$form->isFuture(2, 'truthy-class', 'falsy-class'): string
```---
### Blade Example
Data will be injected into the view as well as the form itself allowing you to access the form values and other helper methods.
```php
namespaced('onboarding');
$form->canNavigateBack(true);
``````blade
@switch($form->currentStep())
@case(1)
Name
@error('name')
{{ $errors->first('name') }}
@enderror
@break
@case(2)
Role
@error('role')
{{ $errors->first('role') }}
@enderror
@break
@case(3)
Review your submission:
Name: {{ $form->getValue('name') }}
Role: {{ $form->getValue('role') }}
@break
@endswitch
@if($form->isLastStep())
Save
Reset
@else
Continue
@endif```
### Vue Example
Form state and data will be returned as JSON when no view is
specified or the request prefers JSON. You can combine both
techniques to use Vue within blade as well.```html
@{{ options.title }}
@{{ options.message }}
Continue
Continue
Continue
Review Submission
Name: @{{ form.name }}
Role: @{{ form.role }}
Email: @{{ form.email }}
Phone: @{{ form.phone }}
Save
Reset
Done
```
#### Example Form Component
```vue
export default {
name: 'Form',
props: ['action'],
data: () => ({
errors: {},
options: {},
form: {form_step: 1},
}),
methods: {
reset() {
this.form.reset = 1
this.submit()
},
back(step) {
if (step < this.form.form_step) {
this.fetch({form_step: step})
}
},
fetch(params = {}) {
axios
.get(this.action, {params})
.then(this.onResponse)
.catch(this.onError)
},
submit() {
axios
.post(this.action, this.form)
.then(this.onResponse)
.catch(this.onError)
},
onError({response}) {
this.errors = (response.data.errors || response.data.exception)
},
onResponse({data}) {
this.errors = {}
this.options = (data.data || {})
this.form = (data.form || {})
},
},
created() {
this.fetch()
}
}
```
#### Example Input Component
```vue
export default {
name: "Input",
props: ['name', 'label', 'value', 'errors'],
computed: {
field: {
get() {
return this.value
},
set(val) {
return this.$emit('input', val)
}
}
}
}
{{ label || name }}
{{ errors[name][0] }}
```
#### Example Select Component
```vue
export default {
name: "Select",
props: ['name', 'label', 'value', 'errors', 'options'],
computed: {
field: {
get() {
return this.value
},
set(val) {
return this.$emit('input', val)
}
}
}
}
{{ label || name }}
Please select one
{{ option }}
{{ errors[name][0] }}
```