Eureka Tutorial – Start Building Easy iOS Forms

This Eureka tutorial will teach you how Eureka makes it easy to build forms into your iOS app with various commonly-used user interface elements. By Nicholas Sakaimbo.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

Selecting the Repeat Frequency

Any worthwhile to-do item interface should let the user specify whether a task is recurring, and at what interval. You will make use of Eureka's PushRow class for this. PushRow accepts an array of options of a given type. Eureka will then take care of generating the supporting interface and navigation to enable the user to make a selection.

Add a PushRow right below the date picker, in the same section:

<<< PushRow<String>() { //1
          $0.title = "Repeats" //2
          $0.value = viewModel.repeatFrequency //3
          $0.options = viewModel.repeatOptions //4
          $0.onChange { [unowned self] row in //5
          if let value = row.value {
            self.viewModel.repeatFrequency = value
          }
        }
     }

By now, some of the above steps should look a little familiar:

  1. Add a new PushRow to the most-recently instantiated section. PushRow is a generic class, so you need to specify that you're using it with type String in angle brackets.
  2. Again, to make the purpose of this selector clear to the user, set its title to "Repeats".
  3. Initialize the row's value with the view model's repeatFrequency property to show the current selection.
  4. As you might have guessed, the options of a PushRow represent the list of possible values the user can select. Set this to viewModel.repeatOptions, an array of strings that have been declared in the starter project. If you Command+Click repeatOptions, you'll see the repeat options are: never, daily, weekly, monthly and annually.
  5. Whenever the row's value changes, update viewModel with the newly-selected value.

Build and run. You'll see that a new row titled Repeats is added to the form.

Tapping this row transports you to a view where you can select from the provided options. Upon selection, you're popped back to the root task edit view with your selection reflected.

Adding a Priority Selector

A user should be able to specify how important an item is. To do that, you'll use a SegmentedRow which embeds a UISegmented​Control into a UITableViewCell.

Below the code you just added for the PushRow, add the following:

+++ Section()
      <<< SegmentedRow<String>() {
        $0.title = "Priority"
        $0.value = viewModel.priority
        $0.options = viewModel.priorityOptions
        $0.onChange { [unowned self] row in
          if let value = row.value {
            self.viewModel.priority = value
          }
        }
      }

The code above adds a SegmentedRow with a String type parameter to the form. By now, the rest of the steps outlined should look familiar. Like the row setup you've seen so far, you're setting the title, value, options and onChange(_:) properties using the viewModel.

Build and run. You now have a fully-functioning segmented control to set the item's priority, where "!", "!!" and "!!!" correspond to low-, medium- and high-importance, respectively.

Setting a Reminder with an Alert Row

The interface requires a way for the user to select when they will be reminded of an upcoming item, such as "30 minutes before," "1 hour before", or "1 day before". You could use a PushRow, as in the repeat frequency example. However, to explore the variety of Eureka's components, you will use an alert controller instead. And guess what? Eureka has an AlertRow for that!

Add the following just below the SegmentedRow:

<<< AlertRow<String>() {
        $0.title = "Reminder"
        $0.selectorTitle = "Remind me"
        $0.value = viewModel.reminder
        $0.options = viewModel.reminderOptions
        $0.onChange { [unowned self] row in
          if let value = row.value {
            self.viewModel.reminder = value
          }
        }
      }

The setup of this row is identical to the rows you have added until this point. However, you also set the additional selectorTitle property, which is the title of the UIAlertController presenting the list of options.

Note: Eureka can also display alert controllers with the ActionSheet style using ActionSheetRow in a similar fashion.

Note: Eureka can also display alert controllers with the ActionSheet style using ActionSheetRow in a similar fashion.

Build and run. When you tap the row titled Reminder, an alert controller is presented, allowing you to select the desired reminder time. You didn't even have to write any UIAlertController code!

Validation

Still on the task edit view, tap-to-edit the description text field. Delete all characters until you can see the placeholder text, then hit Save. Your to-do item no longer has a title!

It would be a good idea to make sure the user cannot leave the description blank. Back in viewDidLoad(), find the code where you added a TextRow. Add the following just before the closing bracket of the TextRow closure (and after the onChange closure):

$0.add(rule: RuleRequired()) //1
$0.validationOptions = .validatesOnChange //2
$0.cellUpdate { (cell, row) in //3
  if !row.isValid {
    cell.titleLabel?.textColor = .red
  }
}
  1. Initialize and add a RuleRequired to the TextRow object. This is one of the validation rules provided with Eureka to handle required input in a form. It indicates that a value must be provided in the field to pass validation.
  2. Set the row's validationOptions to .validatesOnChange, meaning the validation rule will be evaluated as the row's value changes.
  3. If the value of the row is not valid, set the row's title color to red to red to alert the user.

Note: You can also add custom rules to handle use cases more specific to our needs, as described in Eureka's documentation.

Note: You can also add custom rules to handle use cases more specific to our needs, as described in Eureka's documentation.

To make sure the user can't leave the editing screen with an invalid entry, replace the contents of the saveButtonPressed(_:) method with the following:

if form.validate().isEmpty {
  _ = navigationController?.popViewController(animated: true)
}

Eureka has a validate() method that returns an array of any validation errors from all rows with validation rules. If this array is empty, your form has no errors and you can pop the view controller from the navigation stack.

Build and run, and delete the contents of the Description field again. This time, the field label turns red, and the Save button won't allow you to leave until the issue is resolved.

Adding More Pizazz with Eureka Plugins

A plugin is a custom Row component just like any of the rows already included with the Eureka library. You can browse the plugins created by the community at the Eureka Community Portal.

Let's say you wanted the user to be able to attach an image to a to-do item as a visual aid. Sounds like a job for the ImageRow plugin!

The plugin has already been included in the starter project using the CocoaPods installation instructions found in the plugin readme. To integrate it, start by adding the following import statement to the top of EditToDoItemViewController.swift:

import ImageRow

Note: This plugin requires the addition of the NSCameraUsageDescription and NSPhotoLibraryUsageDescription keys in the project's info.plist file. This has already been done for you in the starter project.

Note: This plugin requires the addition of the NSCameraUsageDescription and NSPhotoLibraryUsageDescription keys in the project's info.plist file. This has already been done for you in the starter project.

In viewDidLoad(), add a new section with an ImageRow to the form:

  +++ Section("Picture Attachment")
  <<< ImageRow() {
    $0.title = "Attachment"
    $0.sourceTypes = [.PhotoLibrary, .SavedPhotosAlbum, .Camera] //1
    $0.value = viewModel.image //2
    $0.clearAction = .yes(style: .destructive) //3
    $0.onChange { [unowned self] row in //4
      self.viewModel.image = row.value
    }
}

Taking it comment-by-comment:

  1. In the initialization closure, allow the user to select images from their Photo Library, Saved Photos album, or camera if available.
  2. If an image is already attached to this to-do item, use it to initialize the row's value.
  3. Present the "Clear Photo" option with the "destructive" style to indicate that image data may be permanently destroyed when a photo attachment is cleared (when using the camera roll, for example).
  4. As with the previous examples, update the viewModel.image when a new value is set.

Build and run. Tap the row titled Attachment, pick Photo Library from the action sheet, then select an image attachment. The results will be shown in a preview on the Attachment cell.

Eureka Tutorial

Nicholas Sakaimbo

Contributors

Nicholas Sakaimbo

Author

Jeff Rames

Tech Editor

Chris Belanger

Editor

Andy Obusek

Final Pass Editor and Team Lead

Over 300 content creators. Join our team.