Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Eureka forms: how do you limit the number of rows in a multivalued section?

I am using Eureka to build a form in iOS using Swift. I have created a multivalued section, e.g.:

form +++ MultivaluedSection(multivaluedOptions: [.Insert, .Delete], header: "My Header", footer: "My footer") { section in
    section.tag = "mySectionTag"
    section.addButtonProvider = { _ in
        return ButtonRow() { row in
                row.title = "Add row"
        }
    }

    section.multivaluedRowToInsertAt = { index in
        return TimeInlineRow() { row in
                row.title = "My row title"
        }
    }
    // initialize form with any times that have already been set previously, times: [Date]
    for time in times {
    section <<< TimeInlineRow(tag) { row in
        row.value = time
        row.title = "My row title"
    }
}

I would like to limit the number of rows you can insert into my multi valued section. Was thinking about doing it by hiding the ButtonRow using some kind of Condition but I'm not sure how to connect it. Alternatively could just present an alert if you tap the button row when the count of values() in the section is too high, but then how do you block the actual inserting?

Was also considering that I could do something inside multivaluedRowToInsertAt based on index but still not sure what.

Looked through the issues and was surprised not to find anything on this already, so I can only assume I'm missing something obvious.

Another thought I had was to set a Condition on the ButtonRow in the addButtonProvider that returns true if the row with a certain max row tag (that I create) is not nil in the form (i.e. no such row exists), and then in the multivaluedRowToInsertAt it would check if the index is greater than the max allowable index and if so it applies the max tag when creating that row. But it seems the green + insert button is automatically applied to the last row of the section regardless of the type. Then I tried changing the multivaluedOptions to just .Delete when the max rows are reached but I'm having trouble figuring out how to get it to go back to allowing inserting after a row is deleted.

Also tried putting a condition on the ButtonRow's disabled property based on a similar method as above (with a max row) but it also runs into duplicate row tag issues and the green add button still responds to taps, and the showInsertIconInAddButton property has no effect.

Even if I get this method working, it seems unnecessarily convoluted and I would have expected there to be a much simpler solution since it seems like this would be the kind of functionality a lot of people would need.

like image 564
shim Avatar asked Dec 21 '17 20:12

shim


2 Answers

As laid out in Mahbub's answer and hinted at in the original question, one can check the index in the multivaluedRowToInsertAt block and update the multivaluedOptions and hide the button row accordingly.

Properties in FormViewController:

private var myButtonRow: ButtonRow! // Can also just refer to it by tag
let kMaxCount = 5

Inside a setup function in FormViewController: (not shown, setting up the section / button row / add provider etc)

section.multivaluedRowToInsertAt = { index in
    if index >= self.kMaxCount - 1 {
        section.multivaluedOptions = [.Delete]                    

        self.myButtonRow.hidden = true

        DispatchQueue.main.async() { // I'm not sure why this is necessary
            self.myButtonRow.evaluateHidden()
        }
    }

    return TimeRow() { row in // any row type you want — although inline rows probably mess this up
        row.title = title
        row.value = Date()
    }
}

The changes to the button row inside multivaluedRowToInsertAt didn't seem to take hold until the 6th row was added, regardless of when the hidden method is called and what the max count is set to, and the last row that inserts goes in the second last place. So then I tried the code as written above, with a dispatch call delaying evaluateHidden() and it seems to work. I'm not sure why, presumably some conflicting race condition. Note, when the insert method is called it is on the main thread, so it's not about changing UI on a background thread.

Then for when rows are deleted there is a function called rowsHaveBeenRemoved you can override in a FormViewController subclass that is called whenever a row (in any section) is removed:

override func rowsHaveBeenRemoved(_ rows: [BaseRow], at indexes: [IndexPath]) {
    super.rowsHaveBeenRemoved(rows, at: indexes)
    if let index = indexes.first?.section, let section = form.allSections[index] as? MultivaluedSection {
        if section.count < kMaxCount {
            section.multivaluedOptions = [.Insert, .Delete]
            myButtonRow.hidden = false // or could 
            myButtonRow.evaluateHidden()
        }
    }
}
like image 164
shim Avatar answered Oct 16 '22 10:10

shim


This is how can you limit the number of rows in a multivalued section:

section.multivaluedRowToInsertAt = { index in

    if index > 2 {
        let multiValuedSection = self?.form.sectionBy(tag: "MultivaluedSectionTag") as! MultivaluedSection
        multiValuedSection.multivaluedOptions = [.Reorder, .Delete]

        self?.form.rowBy(tag: "AddButtonProviderTag")?.hidden = true
        self?.form.rowBy(tag: "AddButtonProviderTag")?.evaluateHidden()
    }

    // Do other stuff
}
like image 3
Mahbub Morshed Avatar answered Oct 16 '22 10:10

Mahbub Morshed