Code Monkey home page Code Monkey logo

rsformview's Introduction

Build Status Maintainability Test Coverage License

RSFormView

What is it?

RSFormView is a library that helps you build fully customizable forms for data entry in a few minutes.

Installation

RSFormView is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'RSFormView', '~> 2.1.1' 

Usage

  1. Add a FormView to your view controller, you can do this either programatically or via Storyboards.

Programatically:

let formView = FormView(frame: frame)
view.addSubview(formView)

Storyboards: Add a UIView to your view controller and change the class name to FormView and the module to RSFormView.

  1. Set your view controller as FormViewDelegate:
import RSFormView

class YourViewController: UIViewController, FormViewDelegate { ... }

and implement

func didUpdateFields(in formView: FormView, allFieldsValid: Bool)

This function will be called any time a user enters any data in the form, so it's a great place to update other views dependent on the entered data.

  1. Set your view controller as the FormView delegate
formView.delegate = self
  1. Set a FormViewModel to your formView

A FormViewModel can be any class that implements the FormViewModel delegate. For a class to implement FormViewModel delegate you only need to define an array of FormItem. Each FormItem will determine the behavior and validation of each text field in your form. Out of the box, RSFormView provides the following subclasses of FormItem:

  • TextCellItem: A single label, or a "section header"
  • TextFieldCellItem: A single text field.
  • TwoTextFieldCellItem: Two text fields.

You can add your own custom FormItems, check the Custom Items section for more information.

FieldType

fieldType is a FormField property that determines the behaviour of the represented TextField.

Cases:

  • email: Will present the email keyboard when the field is selected and validate that the text entry is in an email format
  • date: Will present a native date picker when the field is selected and validate that the entry is not empty
  • integer: Will present the numeric keyboard when the field is selected and validate that the text entry can be casted to Int
  • double: Will present the decimal keyboard when the field is selected and validate that the text entry can be casted to Double, pass the max decimal places as a parameter of this enum case
  • password: Will mask the text entry in UI and validate that the text entry is not empty
  • usPhone: Will decorate the text entry with slashes (111-111-1111) and validate that the text entry is in a valid US phone number format

Check FieldType definition for more supported cases.

ValidationType

validationType is a FormField property that determines the validation behaviour of the represented TextField. Different FieldTypes provide different default validations but the validation can be overriden by setting a ValidationType to the FormField.

Cases:

  • nonEmpty: Will mark the field invalid if the text entry is empty
  • none: No validation will be made, the field will never be marked invalid unless manually made so
  • integer: Will mark the field invalid if the text entry is not an integer
  • double: Will mark the field invalid if the text entry is not a double, max 2 decimal places
  • usState: Will validate that the text entry matches the name or abbreviation of any of the US states
  • custom: Pass this case a block with your custom validation.

Custom example:

yourFormField.validationType = .custom(evaluator: { [weak self] updatedValue in
  let otherFormField = self?.fields().first { $0.name == "OtherFormFieldName" }
  let otherFormFieldValue = otherFormField?.value ?? ""
  return updatedValue.count > 5 && updatedValue == otherFormFieldValue
})
//In this example the field will be marked valid if the text entry has mora characters than 5 and its text entry is the same as the field with identifier "OtherTextFieldName"

FormItem

A FormItem defines the basic behaviour of a row which is then specialized by subclassing it. You should never use instances of FormItem directly, RSFormView provides the following subclasses of FormItem out of the box:

TextCellItem: A single label, or a "section header" TextFieldCellItem: A single text field. TwoTextFieldCellItem: Two text fields.

  1. One Text Field item:
let birthdateField = FormField(name: "Birthdate field", // the identifier of the field, use this to collect the data later
                               initialValue: "", // the inital value of the field, if its in a date formate it will auto select that date in the picker
                               placeholder: FieldName.birthdate.rawValue, // The placeholder when there's no value and text field title when there is
                               fieldType: .date, //The Type of the field, .date will present a native picker view when tapping on the text field
                               isValid: false, //The initial validation state. The field won't be marked invalid until data is entered or removed
                               errorMessage: "Please enter a birthdate") //The error message to be displayed when the entry is invalid or empty

let formItem = TextFieldCellItem(with: birthdateField)
  1. Two Text Field item:
let firstFormField = FormField(...)
let secondFormField = FormField(...)

let formItem = TwoTextFieldCellItem(firstField: firstFormField, secondField: secondFormField)
  1. Text Cell Item (may be used as a section header or text hint):
let attributedString = NSAttributedString(...)
let formItem = TextCellItem()
formItem.attributedString = attributedString

As an easy way to test the pod, we provide a the class BasaicFormViewModel. It receives a list of items and will show the form without additional customization.

//  birthdateField defined above
        
formView.viewModel = BasicFormViewModel(items: [TextFieldCellItem(with: birthdateField)])

You can see this approach in the VanillaExample folder on this repository.

  1. Configure your form looks

Create a FormConfigurator change any colors or fonts you need and set it to your form view.

let configurator = FormConfigurator()
configurator.textColor = UIColor.lightGray
configurator.validTitleColor = UIColor.blue
configurator.titleFont = UIFont.systemFont(withSize: 13)
...
formView.formConfigurator = configurator

Use the UIColor extension formColor(red: Int, green: Int, blue: Int) to create new UIColors.

let configurator = FormConfigurator()
...
let darkPurple = UIColor.formColor(red: 140, green: 20, blue: 252)
configurator.editingTitleColor = darkPurple
...
formView.formConfigurator = configurator

Choose whether to hide the bottom line by setting the bottom line colors to clear (they are set colored by default)

let configurator = FormConfigurator()
...
configurator.validLineColor = UIColor.clear
configurator.invalidLineColor = UIColor.clear
configurator.editingLineColor = UIColor.clear
...
formView.formConfigurator = configurator

Choose whether to show borders by setting the border colors to the value desired (they are set clear by default). Also set the border width and corner radius as desired.

let configurator = FormConfigurator()
...
configurator.validBorderColor = UIColor.gray
configurator.invalidBorderColor = UIColor.orange
configurator.editingBorderColor = UIColor.darkPurple
configurator.borderCornerRadius = 20
configurator.borderWidth = 2
...
formView.formConfigurator = configurator

Disable tableView scrolling, which is enabled by default.

let configurator = FormConfigurator()
...
configurator.isScrollEnabled = false
...
formView.formConfigurator = configurator
  1. Collect data

Any text entry made in your form will be collected in your FormViewModel items. Since you may have more than one text field per item a better way for collecting your data is making use of the fields() function of the FormViewModel, like this:

var user = User()
formViewModel.fields().forEach {
  switch $0.name {
  case "First Name":
    user.firstName = $0.value
  case "Birthdate":
    user.birthdate = $0.value
  default:
    print("\($0.name): \($0.value)")
  }
}

Custom Form Items

If you need custom fields and the customization possibilities of the FormConfigurator are not enough, you can implement your own Fields. To do so, follow these steps: 1- Create your custom UITableViewCell as you would normally do for any tableView. 2- Instead of subclassing from UITableViewCell, use FormTableViewCell as a base class. 3- Override update and updateErrorState to implement your own UI updates for the field. 4- Create a subclass of FormItem that overrides cellIdentifier and returns a valid reuseID. 5- In your formViewModel implementation, override the customCellSetup callback and register your new cell on the tableView.

If you need an example, you can check the StepperCell and StepperCellItem classes on the Example project.

Server Side Validation

To manually mark fields invalid (for example after a server side validation) you can simply do:

yourFormView.markItemInvalid(fieldName: "EmailFieldName", errorMessage: "Oops, This email is already taken")

After the user makes any edit in the invalid field it will no longer be marked invalid unless the real time validation doesn't pass.

Example App

Clone this repo and run the example app to take a look at some of the RSFormView functionalities

Contribute

To contribute to this library: fork this repository and create a Pull Request from your fork, detailing what are you improving/extending, the approach taken and screenshots to proof functionality added.

You can also open issues in this repository and our team will tackle them as soon as possible.

License

RSFormView is available under the MIT license. See the LICENSE file for more info.

Credits

RSFormView is authored and mantained by Rootstrap and German Stabile with the help of our contributors.

rsformview's People

Contributors

anthfb avatar anthonyfig avatar germanstabile avatar glm4 avatar kevnm67 avatar mcousillas6 avatar smanini1 avatar swiftartery avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

rsformview's Issues

Expiration field type formatting and validation.

Currently, the .expiration field type formats numerical input appending a / between the month and start of the year but allows unlimited character input.

  • What are your thoughts on adding a max character count? Example result: 09/2019.

Seems as though the expected date format would be either: MM/yyyy or MM/yy. Please let me know if I'm misunderstanding this type.

Marking items invalid

There's an issue when marking items invalid manually (for instance Stripe errors), where on the method updateErrorState in TextFieldView, the value for isValid goes from false to true.

Also, some items on TextFieldView should be made public so that the view can be reusable in custom Form Items.

IB Designables issue

When adding a FormView, I get the following error:

Screenshot 2019-06-12 at 11 00 59

I have tried cleaning the project, as well as deleting all derived data. I have also tried pod deintegrate followed by pod install. This happened on both 1.0.1 and 1.1.0.

This is how I have RSFormView set up in Storyboard:
Screenshot 2019-06-12 at 11 00 00

The form still works as expected, just the Storyboard preview is broken.

Also, the README doesn't specify that you have to set the custom module for a FormView to be RSFormView - this confused me for a while.

Missing GitHub project

As per Open Source improvements, GitHub project should be used to professionalize maintenance.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.