stimulus-rails-nested-form icon indicating copy to clipboard operation
stimulus-rails-nested-form copied to clipboard

Allow minimum/maximum configuration

Open JoeWoodward opened this issue 2 years ago • 3 comments

Cocoon would allow developers to define a minimum and maximum number of nested forms, would be nice to do the same here without extending the controller.

i.e. minimum = 1, maximum = 4

If only one nested form is being displayed then the delete button is hidden or disabled If 4 are being displayed then the add button is hidden or disabled

JoeWoodward avatar Jul 09 '21 09:07 JoeWoodward

Hum that sounds cool but I have few questions.

How to find the initial number? How to configure if you want to hide or disable the buttons?

guillaumebriday avatar Jul 09 '21 11:07 guillaumebriday

Ooo I like this.

  1. data attribute set like data-nested-form-target on the template so you can have different min/max for each
  2. would be based on if these data attributes were defined... if not defined then no changes and backwards compatible, if defined then it's based on what those settings are and how many have been added vs the data attribute

😄

darrenterhune avatar Apr 03 '23 19:04 darrenterhune

Just saw this issue, as I also needed to set a limit value. Here's my extension; feel free to take or leave it:

import NestedForm from 'stimulus-rails-nested-form'

export default class extends NestedForm {
  static targets = ['addButton', 'clickAfterAdd']
  static values = {
    limit: Number
  }

  connect () {
    super.connect()
    this.setVisibilityOfAddButton()
  }

  add (e) {
    e.preventDefault()
    const currentCount = this.nestedFormCount()
    if (this.hasLimitValue && currentCount > this.limitValue) return
    super.add(e)
    this.setVisibilityOfAddButton()
    if (!localStorage.isBeingControlledByCapybara && this.hasClickAfterAddTargets) {
      this.clickAfterAddTargets[this.clickAfterAddTargets.length - 1].click()
    }
    this.element.dispatchEvent(new CustomEvent('itemsChanged', { bubbles: true }))
  }

  remove (e) {
    // Since the file removal isn't committed until saved, I guess this is overkill
    // if (!confirm("This will delete the image. Are you sure?")) return
    super.remove(e)
    this.setVisibilityOfAddButton()
    this.element.dispatchEvent(new CustomEvent('itemsChanged', { bubbles: true }))
  }

  // private

  setVisibilityOfAddButton () {
    if (!this.hasAddButtonTarget || !this.hasLimitValue) return
    const currentCount = this.nestedFormCount()
    this.addButtonTarget.classList.toggle('hidden', currentCount > this.limitValue)
  }

  nestedFormCount () {
    return this.nestedForms()
      .filter(el => el.style.display !== 'none').length
  }

  nestedForms () {
    return Array.from(this.element.querySelectorAll(this.wrapperSelectorValue))
  }
}

searls avatar Apr 07 '24 12:04 searls