Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4.1][Feature][Beta] Repeatable field type (aka matrix; aka group) #2266

Merged
merged 26 commits into from
Apr 6, 2020

Conversation

tabacitu
Copy link
Member

@tabacitu tabacitu commented Nov 28, 2019

As talked about in #131, #771 . I think now that v4 allows us to reinitialize fields with Javascript, it's finally its time to shine.

Repeatable

Allows the developer to add a group of Backpack fields (ex: 1 text field, 2 browse fields, 1 wysiwyg field). The user can fill in the fields, add another group with the same fields, or delete groups.

Screenshot:
64406749-451beb80-d08b-11e9-9b0a-c3a4c14edc04

Syntax:

[
  'name' => 'repeatable',
  'label' => 'Entries',
  'type' => 'repeatable',
  'fields' => [
    [
      'name' => 'question',
      'label' => 'Question',
      'type' => 'textarea',
      'wrapperAttributes' => [
         'class' => 'form-group col-md-6'
       ],
    ],
    [
      'name' => 'answer',
      'label' => 'Answer',
      'type' => 'textarea',
      'wrapperAttributes' => [
         'class' => 'form-group col-md-6'
       ],
    ],
  ],
]

By default it compacts the fields and stores the group of fields as JSON. But the saving can be intercepted in the create/update operation, or using a mutator on the model, to make it store the values in a different way.

@tabacitu
Copy link
Member Author

tabacitu commented Nov 28, 2019

Since you can use ALL Backpack field types with this field, it needs extensive testing before it's merged and launched. The testing list should include:

  • all fields work as secondary fields in a repeatable group (test create (+), delete (x), editing and validation failed):
    • address_algolia
    • address_google
    • browse
    • browse_multiple
    • base64_image
    • checkbox
    • checklist
    • checklist_dependency - see Fix checklist_dependency to work inside repeatable #2735;
    • ckeditor
    • color
    • color_picker
    • custom_html
    • date
    • date_picker
    • date_range
    • datetime
    • datetime_picker
    • easymde
    • email
    • enum - doesn't make sense inside Repeatable; use select_from_array instead;
    • hidden
    • icon_picker
    • image
    • month
    • number
    • page_or_link - see #2736;
    • password
    • radio
    • range
    • relationship
    • select (1-n relationship)
    • select_grouped
    • select2 (1-n relationship)
    • select_multiple (n-n relationship)
    • select2_multiple (n-n relationship)
    • select2_nested
    • select2_grouped
    • select_and_order
    • select_from_array
    • select2_from_array
    • select2_from_ajax
    • select2_from_ajax_multiple
    • simplemde
    • summernote
    • table
    • text
    • textarea
    • time
    • tinymce
    • upload - currently impossible; see #2745
    • upload_multiple - currently impossible; see #2745
    • url
    • video
    • view
    • week
    • wysiwyg
  • default value
  • hint
  • wrapperAttributes to make the field smaller/bigger
  • works as a fake field
  • works as a regular (non-fake) field
  • stores the information in the DB as a valid JSON
  • doesn't add nasty slashes to the JSON in the DB
  • stores the information in the DB as a valid JSON when deleting entries
  • stores the information in the DB as a valid JSON when deleting and adding entries
  • stores the information in the DB as a valid JSON when deleting all entries
  • can be used inside tabs
  • can be used multiple times in a form (two or three repeatable fields in one form)
  • click on the PLUS button should move the cursor to the first field in the new group
  • having fields with the same name both inside the actual create/update form and inside a repeatable group should not cause conflicts
  • having the same field type both inside a repeatable field, and outside it (in the main create/update form) should not cause conflicts
  • field works if the attribute has no casting in the model
  • field works if the attribute is casted as array in the model

The following advanced use cases should be tested and documented:

  • intercept the field in the controller, and store the values in a different way (something other than JSON in the db)
  • intercept the field in the model (using a mutator and accessor) and store the values in a different way (something other than JSON in the db)
  • add validation for some secondary fields in a group

@OwenMelbz
Copy link
Contributor

🙌🏼 Image uploaders I’ve found to be the hardest thing for these field types, have you sorted those all okay?

@annadnl
Copy link

annadnl commented Nov 28, 2019

how is the Select2_multiple (n-n relationship with pivot table) supposed to work in here?
should it

  • return one record per group
  • let user add one record per new group?

@diakosavvasn
Copy link

It will released also in the 3.6 version ? Or only 4.0 ?

@tabacitu
Copy link
Member Author

tabacitu commented Dec 2, 2019

@OwenMelbz indeed image uploaders are a bit tricky. I'm on it.

@annadnl I think each select2_multiple input should allow multiple choices per input; say:

  • group 1 (text, number, select2_multiple) - select2_multiple has multiple values
  • group 2 (text, number, select2_multiple) - select2_multiple has multiple values
  • (add new)

Is this what you were asking? I think that's the intuitive way to see it. Don't know about the pivot table though - since most of the time the value of the input won't actually be stored as a column in the DB, but as an attribute in a JSON column, that's the use case I think we should prioritise - storing the value as a JSON.

@diakosavvasn It'll only be available in v4. We've made considerable changes to ALL fields from v3 to v4, specifically to allow us to create a field like this one. In v3 it's "very very VERY" difficult to do. In v4 it's just "very" difficult 😄

@ziming
Copy link
Contributor

ziming commented Dec 3, 2019

Definitely looking forward to this field! Though I wonder if the fields can be vertically stacked instead of horizontal

@tabacitu
Copy link
Member Author

tabacitu commented Dec 3, 2019

@ziming Yes, they're vertically stacked by default - they work exactly the same as Backpack fields inside a create/update operation. You can make more fields fit into one line using wrapperAttributes - that's what I did in the screenshot above (col-md-4).

But by default, with no wrapperAttributes, a field group would look like this:

Screenshot 2019-12-03 at 13 27 54

@ziming
Copy link
Contributor

ziming commented Dec 7, 2019

I get that we can save the data in a different way, but can the data be fetched in a different way too if we don't save it directly to a json column?

@tabacitu
Copy link
Member Author

tabacitu commented Dec 7, 2019

@ziming sure. If you use an Accessor and a Mutator. So on the model you can have:

public function getRepeatableAttribute() {
     // fetch it any way you want
     // but it'll have to be a JSON or PHP array when you return it
}

public function setRepeatableAttribute($value) {
    // store it any way you want
}

@ziming
Copy link
Contributor

ziming commented Dec 7, 2019

Nice, I thought about using the 'default' key initially but yours was a better way.

Shall try this field in 1 of my apps and feedback here on how it goes

@ziming
Copy link
Contributor

ziming commented Dec 8, 2019

Just used it for a test run today with 3 number fields. All of them get saved as strings inside the json array in the end. Wonder if there is an easy way to ensure if the type is number, it gets saved as a number in the json.

I could intercept it at update() or set attribute method but if the field auto cast it based on the sub field type, that might be great

@tabacitu
Copy link
Member Author

tabacitu commented Dec 9, 2019

@ziming indeed that would be nice. I'm wondering if it's an optimization worth doing. Do you see any other fields apart from number that could use front-end casting? Off the top of my head, I can't think of any.

If the "number" field would be only one to use this, I don't think it's worth doing - it would overcomplicate the logic for all fields, when it's easy to fix on the developer side (just cast it in PHP before echoing or using).

@tabacitu tabacitu merged commit 113b180 into 4.1 Apr 6, 2020
@tabacitu tabacitu deleted the multiply-field branch April 6, 2020 07:42
@ziming
Copy link
Contributor

ziming commented Apr 6, 2020

Wow!

@dilneiss
Copy link
Contributor

found something i need in this moment:
i have multiple checkbox, in the repeatead item when i click on the label of the second item, it only check the first checkbox, not the clicked one

reorder the item is missing too, i want the second item to be the first for example, and it is missing

@movilas
Copy link

movilas commented Apr 28, 2020

Sorting (sortable) would be nice to have feature.

@pxpm
Copy link
Contributor

pxpm commented Apr 28, 2020

Sorting (sortable) would be nice to have feature.

#2711 enjoy :)

Thanks for pitching in 👍

tabacitu added a commit that referenced this pull request Apr 29, 2020
When you included multiple fields of this type, using Javascript instead of PHP (for ex inside the repeatable field type), the cropper always showed the preview of the first element, instead of each instance of the field having its own preview area. This fixes that by making the selector use classes instead of IDs.
tabacitu added a commit that referenced this pull request Apr 29, 2020
…tency between them

Also removed one place where base64_image was using ID instead of class.
tabacitu added a commit that referenced this pull request Apr 29, 2020
tabacitu added a commit that referenced this pull request Apr 29, 2020
That way the IDs are different if multiple checkboxes with the same name are on the same page (for example inside a repeatable field).
tabacitu added a commit that referenced this pull request Apr 29, 2020
tabacitu added a commit that referenced this pull request Apr 29, 2020
…ype; makes sure that init functions are only called once per element;
tabacitu added a commit that referenced this pull request May 1, 2020
Addresses #2266 . The checklist field now loads its options using PHP, but it checks those options using JavaScript. The value of the field is now stored in a hidden input, instead of individual checkboxes like it was doing before. The syncPivot() method has been amended to also support passing the connected entries as a JSON, not only a direct array. This was done because when storing multiple values inside one hidden input, the value that reaches PHP is a JSON. But previously, when there were individual inputs for each value, the value that reached PHP was a PHP array. This is a non-breaking change, and I expect it will also help with other fields - if we wish to store multiple IDs inside one hidden field.
tabacitu added a commit that referenced this pull request May 3, 2020
tabacitu added a commit that referenced this pull request May 3, 2020
Also adds select2_nested example inside MonsterCrudController.
tabacitu added a commit that referenced this pull request May 4, 2020
@joaojoyce
Copy link
Contributor

Hi @tabacitu.

This is such a great feature.

I've noticed that images get into a base64 array. Does it work with image uploads as there's no place to set the mutator?

Thank you.

@iMokhles
Copy link
Contributor

iMokhles commented Jun 30, 2020

So it's an amazing field but i had issue with image field as @joaojoyce
but i i was able to make it works like that.

Repeatable Field Setup
Capture d’écran 2020-06-30 à 19 15 53

Repeatable Field Mutator
Capture d’écran 2020-06-30 à 19 06 49

Image Setter same as documentation with some comments to serve my need
Capture d’écran 2020-06-30 à 19 12 27

Images saved in database like that
Capture d’écran 2020-06-30 à 19 10 18

And also uploaded and saved to my disk correctly
Capture d’écran 2020-06-30 à 19 11 07

Hope it helps someone and hope it make sense for you @joaojoyce

@pxpm pxpm assigned pxpm and unassigned tabacitu Oct 20, 2021
@tabacitu tabacitu mentioned this pull request Nov 24, 2021
9 tasks
@tabacitu
Copy link
Member Author

Update - Pedro has just finished refactoring the repeatable, we now have nested array validation starting with Backpack 4.2 🎉 So we can do things like 'testimonial.*.name' => 'required|min:5|max:256' 🎉🎉🎉 So much simpler!

This refactor also opens up the possibility for us to maybe make image, upload and upload_multiple work inside repeatable (still working on that one) 😱

I've decided to create one issue for all things repeatable - see #3953

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.