Hot questions for Using Eureka in generics

Question:

Im having different functions for creating PushRow with different types. it includes both string type and custom defined types also. How to merge these functions to a single one which accept generic parameter for creating PushRow

fileprivate func createPushRow1() {     
    form +++ Section(label)
        <<< PushRow<String>(String(typeId)) {
        $0.title = label.lowercased()
        $0.selectorTitle = "Pick " + label.lowercased()
        $0.options = optionList
        }.onChange({ [unowned self] row in
           row.value = row.value
        })
}

fileprivate func createPushRow2() {
     self.form +++ Section(label)
          <<< PushRow<Priority>(String(typeId)) {
          $0.title = label.lowercased()
          $0.selectorTitle = "Pick " + label.lowercased()
          $0.options = priorityList
          $0.displayValueFor = {
              guard let priority = $0 else { return nil }
              return priority.name
          }
          $0.onChange({ [] row in
              row.value = row.value
          })
     }
}

Answer:

PushRow options require conformance to Equatable. So assuming your Priority class conforms to Equatable, you can use the follow function which takes a generic equatable type as a parameter to create a PushRow.

func createPushRow<T: Equatable>(type: T.Type, options: [T]) {

    self.form +++ Section(label)

        <<< PushRow<T>(String(typeId)) {

            $0.title = label.lowercased()
            $0.selectorTitle = "Pick " + label.lowercased()
            $0.options = options
        }
}

You can simply use the function like this.

self.createPushRow(type: String.self, options: ["option A", "option B"])

However, you need to be careful on your PushRow tag String(typeId) though, Eureka does not accept rows with the same tag, so you will probably want to pass unique row tag as another parameter in the generic function.

Updated

You can simply conform your Priority struct to both Equatable and CustomStringConvertible.

struct Priority: Equatable, CustomStringConvertible {

    let id: Int
    let name: String

    var description: String {
        return self.name
    }

    static func == (lhs: Priority, rhs: Priority) -> Bool {
        return lhs.id == rhs.id
    }
}

Question:

I have use Eureka for my form but i am facing an issues. I setup the form using these code

form +++ Section("Add Event")
        <<< TextRow("Event"){ row in
            row.title = "Event"
            row.placeholder = "Enter Event Name Here"
        }
        <<< DateRow("Date"){
            $0.title = "Date"
            $0.value = selectedDate

        }
        <<< TimeRow("Time"){
            $0.title = "Time"
            $0.value = selectedDate

    }
    let locationSearchTable = storyboard!.instantiateViewController(withIdentifier: "eventLocation") as! EventLocationViewController

    form +++ Section("Location")
        <<< CustomPushRow<EventLocationViewController>(){
            $0.title = "Location"
            $0.presentationMode = .segueName(segueName: "eventLocation" ,controllerProvider: locationSearchTable, onDismiss: nil)

    }

here the custom push row class

public final class CustomPushRow<T: Equatable>: SelectorRow<PushSelectorCell<T>, SelectorViewController<T>>, RowType {

public required init(tag: String?) {
    super.init(tag: tag)
    presentationMode = .show(controllerProvider: ControllerProvider.callback {
        return SelectorViewController<T>(){ _ in }
        }, onDismiss: { vc in
            print("On Dimiss")
            _ = vc.navigationController?.popViewController(animated: true)
    })
}

}

and when i wanna change the value of the form i use this method to change

    let eventName : TextRow? = form.rowBy(tag:"Event")
    eventName?.value = "asdasadsds"

but when i wanna change the custom push row i am having this issues cannot convert value of type 'BaseRow?' to specified type 'CustomPushRow?' when i do this

   let row : CustomPushRow? = form.rowBy(tag: "Location")

How can i change the value of the CustomPushRow


Answer:

Try taking your info a different way (a tip I got from Swift: How to get form values using Eureka form builder? helped me with another "cannot convert value of...." issue)

To READ the value on a row that gives you the error message:

  1. Be sure to set tags on all your elements ($0.tag = "whatever")

  2. instead of

    let row : CustomPushRow? = form.rowBy(tag: "Location")

use

let dict = self.form.values(includeHidden: true)

Then you can see the value with something like

print(dict["whatever"])

Now, the other part of your question asked about SETTING the value, which is a different thing in Eureka.

From the docs (https://github.com/xmartlabs/Eureka#how-to-set-the-form-values-using-a-dictionary):

How to set the form values using a dictionary

Invoking setValues(values: [String: Any?]) which is exposed by Form class.

For example:

form.setValues(["IntRowTag": 8, "TextRowTag": "Hello world!", "PushRowTag": Company(name:"Xmartlabs")])

Where "IntRowTag", "TextRowTag", "PushRowTag" are row tags (each one uniquely identifies a row) and 8, "Hello world!", Company(name:"Xmartlabs") are the corresponding row value to assign.

Question:

I am unable to hide the validation errors based on the value of each SegmentedRow (upon switching).

Edit: Eureka version 4.0.1

What I have tried: Switching over the val and comparing to each ImportSelectionType

I can hide them for an individual SegmentedRow value: code below.

 $0.hidden = Condition.function(["segment"], { form in
                        if let val = form.rowBy(tag: "segment")?.baseValue as? String {
                            // TODO: make it work in all cases
                            return val != ImportSelectionType.keystore.title
                        }

                        return false
                    })

How could I make this generic so it will work in all cases?

Edit: ImportSelectionType is declared like so. enum ImportSelectionType { case keystore case privateKey case mnemonic case watch

var title: String {
    switch self {
    case .keystore:
        return "Keystore"
    case .privateKey:
        return "Private Key"
    case .mnemonic:
        return "Mnemonic"
    case .watch:
        return "Watch"
    }
}

init(title: String?) {
    switch title {
    case ImportSelectionType.privateKey.title?:
        self = .privateKey
    case ImportSelectionType.watch.title?:
        self = .watch
    case ImportSelectionType.mnemonic.title?:
        self = .mnemonic
    default:
        self = .keystore
    }
}

}


Answer:

It seems updating to Eureka 4.1.1 solved the issue.