1Repeater::make()2 ->type('video')
1<x-twill::repeater2 type="video"3/>
1@formField('repeater', ['type' => 'video'])
Option | Description | Type | Default value |
---|---|---|---|
type | Type of repeater items | string | |
name | Name of the field | string | same as type |
max | Maximum amount that can be created | number | null (unlimited) |
buttonAsLink | Displays the Add button as a centered link |
boolean | false |
reorder | Allow reordering of repeater items | boolean | true |
Repeater fields can be used inside as well as outside the block editor.
Inside the block editor, repeater blocks share the same model as regular blocks. By reading the section on the block editor first, you will get a good overview of how to create and define repeater blocks for your project. No migration is needed when using repeater blocks. Refer to the section titled Adding repeater fields to a block for a detailed explanation.
Outside the block editor, repeater fields are used to save hasMany
or morphMany
relationships.
Inline repeaters are Form builder only.
This field will allow you to create repeaters inline. This works for json repeaters or regular repeaters and can both be used in block components and page forms.
While in theory these can be nested, nested inline repeaters only work on blocks not controller forms.
When using a json repeater in a block, the setup is straightforward and all you have to do is add the inline repeater to your block form.
1<?php 2namespace App\View\Components\Twill\Blocks; 3 4use A17\Twill\Services\Forms\Fields\Wysiwyg; 5use A17\Twill\Services\Forms\Form; 6use A17\Twill\Services\Forms\Fields\Input; 7use A17\Twill\Services\Forms\InlineRepeater;use A17\Twill\View\Components\Blocks\TwillBlockComponent; 8use Illuminate\Contracts\View\View; 9 10class Example extends TwillBlockComponent11{12 public function render(): View13 {14 return view('components.twill.blocks.example');15 }16 public function getForm(): Form17 {18 return Form::make([19 InlineRepeater::make()->name('links') 20 ->fields([21 Input::make()->name('title'),22 Input::make()->name('url'),23 ]) 24 ]);25 }26}
On a regular controller form you have to still setup the handleJsonRepeaters.
When you are working with relations, you have to setup a little bit more.
Below is a full fledged example coming from the portfolio
installable example:
1<?php 2 3namespace App\Http\Controllers\Twill; 4 5use A17\Twill\Http\Controllers\Admin\ModuleController as BaseModuleController; 6use A17\Twill\Models\Contracts\TwillModelContract; 7use A17\Twill\Services\Forms\Fields\BlockEditor; 8use A17\Twill\Services\Forms\Fields\Input; 9use A17\Twill\Services\Forms\Fields\Repeater;10use A17\Twill\Services\Forms\Form;11use A17\Twill\Services\Forms\InlineRepeater;12use App\Models\Partner;13 14class ProjectController extends BaseModuleController15{16 protected function setUpController(): void17 {18 $this->setModuleName('projects');19 }20 21 public function getForm(TwillModelContract $model): Form22 {23 return Form::make([24 Input::make()25 ->translatable()26 ->name('description'),27 28 // Inline repeater that can select existing entries.29 InlineRepeater::make()30 ->label('Partners')31 ->name('project_partner')32 ->triggerText('Add partner') // Can be omitted as it generates this.33 ->selectTriggerText('Select partner') // Can be omitted as it generates this.34 ->allowBrowser()35 ->relation(Partner::class)36 ->fields([37 Input::make()38 ->name('title')39 ->translatable(),40 Input::make()41 ->name('role')42 ->translatable()43 ->required(),44 ]),45 Repeater::make()->type('comment'), // Regular repeater using a view.46 // Regular repeater for creating items without a managed model.47 InlineRepeater::make()48 ->name('links')49 ->fields([50 Input::make()51 ->name('title'),52 Input::make()53 ->name('url')54 ]),55 56 BlockEditor::make()57 ]);58 }59}
The following example demonstrates how to define a relationship between Team
and TeamMember
modules to implement
a team-member
repeater.
position
feature on the TeamMember
module:1php artisan twill:make:module Team2php artisan twill:make:module TeamMember -P
create_team_members_tables
migration. Add the team_id
foreign key used for the TeamMember—Team
relationship: 1public function up() 2{ 3 Schema::create('team_members', function (Blueprint $table) { 4 /* ... */ 5 6 $table->foreignId('team_id') 7 ->constrained() 8 ->onUpdate('cascade') 9 ->onDelete('cascade');10 });11}
1php artisan migrate
Team
model. Define the members
relationship. The results should be ordered by position:1class Team extends Model2{3 /* ... */4 5 public function members()6 {7 return $this->hasMany(TeamMember::class)->orderBy('position');8 }9}
TeamMember
model. Add team_id
to the fillable
array:1class TeamMember extends Model2{3 protected $fillable = [4 /* ... */5 'team_id',6 ];7}
TeamRepository
. Override the afterSave
and getFormFields
methods to process the repeater field:
updateRepeaterMorphMany
in place of updateRepeater
1class TeamRepository extends ModuleRepository 2{ 3 /* ... */ 4 5 public function afterSave($object, $fields) 6 { 7 $this->updateRepeater($object, $fields, 'members', 'TeamMember', 'team-member'); 8 parent::afterSave($object, $fields); 9 }10 11 public function getFormFields($object)12 {13 $fields = parent::getFormFields($object);14 $fields = $this->getFormFieldsForRepeater($object, $fields, 'members', 'TeamMember', 'team-member');15 return $fields;16 }17}
Create file resources/views/twill/repeaters/team-member.blade.php
:
1@twillRepeaterTitle('Team Member') 2@twillRepeaterTrigger('Add member') 3@twillRepeaterGroup('app') 4 5<x-twill::input 6 name="title" 7 label="Title" 8 :required="true" 9/>10 11...
Update file resources/views/twill/teams/form.blade.php
:
1@extends('twill::layouts.form')2 3@section('contentFields')4 ...5 6 <x-twill::repeater7 type="team-member"8 />9@stop
Add both modules to your twill.php
routes. Add the Team
module to your twill-navigation.php
config and you are
done!
In Twill >= 2.5, you can use the @twillRepeaterTitleField
directive to include the value of a given field in the title
of the repeater items. This directive also accepts a hidePrefix
option to hide the generic repeater title:
1@twillRepeaterTitle('Person') 2@twillRepeaterTitleField('name', ['hidePrefix' => true]) 3@twillRepeaterTrigger('Add person') 4@twillRepeaterGroup('app') 5 6<x-twill::input 7 name="name" 8 label="Name" 9 :required="true"10/>