An open API service indexing awesome lists of open source software.

https://github.com/retro/can-form

Form Library for CanJS
https://github.com/retro/can-form

Last synced: about 1 month ago
JSON representation

Form Library for CanJS

Awesome Lists containing this project

README

        

# can-form

Can-Form is a form component for the CanJS framework. It takes care of the form validation and error reporting while allowing you to do things the "CanJS way".

Notable features:

- Form based validations (with support for nested objects)
- Composable / nestable form
- Error reporting
- Intelligent validation management - validates only the fields that user changed, or all of them if the form is submitted
- Behaves like a real form (pressing enter in the input field will submit the form)
- Behaves like a Component (can.Component)

## Form based validations

You can add validations to the form component by using the `validate` property:

FormComponent.extend({
tag : 'simple-form',
template : '',
validate : {
username : [FormComponent.validationRules.presenceOf()],
password : [FormComponent.validationRules.presenceOf()]
}
});

This is a simple form example, that validates presence of `username` and `password` attributes.

You initialize it like this:




Submit

Context inside the form template will be set to whatever was passed in the `map` attribute of the form tag.

Form will automatically wrap your content in the `form` element so you shouldn't include it yourself.

Although the data will be validated, the errors will not be show. To show the errors, use the `errors` helper:



{{#errors 'username'}}


    {{#this}}
  • {{ . }}

  • {{/this}}

{{/errors}}

{{#errors 'password'}}

    {{#this}}
  • {{ . }}

  • {{/this}}

{{/errors}}
Submit

Now the errors will be shown whenever the user changes the input or submits the form.

## Composable / nestable forms

When you have a nested data structure it can be tricky to keep track of your fields and errors - modelling the form after your data can be a pain.

can-form allows you to nest the form components one inside another. Let's say that you want add ability for your users to add their social network accounts in the form.

can-form comes with the default form component called `form-for` that can be used for cases like this:



{{#errors 'username'}}


    {{#this}}
  • {{ . }}

  • {{/this}}

{{/errors}}

{{#errors 'password'}}

    {{#this}}
  • {{ . }}

  • {{/this}}

{{/errors}}

{{#each socialNetworks}}


// error reporting code here

// error reporting code here

{{/each}}
Submit

This might look a bit confusing at first so let me explain what happens here:

- we itereate through all elements in the `socialNetworks` array
- we create a new `form-for` element for each item in the array
- we use the `path` attribute to hint what is the path from the parent context, this is needed for the error reporting and validations
- finally we have our inputs, but these inputs include only the name of the attribute in the current context - this makes forms reusable

If we wanted to validate the `socialNetworks` array we can add the following to our component constructor:

FormComponent.extend({
tag : 'simple-form',
template : '',
validate : {
username : [FormComponent.validationRules.presenceOf()],
password : [FormComponent.validationRules.presenceOf()],
'socialNetworks.*.username' : [FormComponent.validationRules.presenceOf()],
'socialNetworks.*.network' : [FormComponent.validationRules.presenceOf()]
}
});

When you use the `socialNetworks.*.network` syntax it sets up the validation for the `network` property of each item in the `socialNetworks` array (This syntax is based on the path syntax generated by the can.Map events);

### Alternate approach

If we wanted to reuse the form component for the social network map, we could create it's own component:

FormComponent.extend({
tag : 'social-network',
template : socialNetworkTemplate,
validate : {
username : [FormComponent.validationRules.presenceOf()],
network : [FormComponent.validationRules.presenceOf()]
}
})

For the view we can just use the following code:


{{#errors 'network'}}


    {{#this}}
  • {{ . }}

  • {{/this}}

{{/errors}}

{{#errors 'username'}}

    {{#this}}
  • {{ . }}

  • {{/this}}

{{/errors}}

Now we can include the `social-network` component inside the `simple-form`:



{{#errors 'username'}}


    {{#this}}
  • {{ . }}

  • {{/this}}

{{/errors}}

{{#errors 'password'}}

    {{#this}}
  • {{ . }}

  • {{/this}}

{{/errors}}

{{#each socialNetworks}}


{{/each}}
Submit

This approach allows you to reuse forms across different context while keeping the same validations and behavior.