GithubHelp home page GithubHelp logo

adopted-ember-addons / ember-cp-validations Goto Github PK

View Code? Open in Web Editor NEW
443.0 15.0 171.0 16.01 MB

Ember computed property based validations

Home Page: https://adopted-ember-addons.github.io/ember-cp-validations/

License: BSD 3-Clause "New" or "Revised" License

JavaScript 94.99% HTML 0.63% SCSS 2.44% Handlebars 1.94%
ember ember-addon validations

ember-cp-validations's Introduction

Ember CP Validations

Build Status npm version Download Total Ember Observer Score

An EmberJS validation framework that is completely and utterly computed property based.

Compatibility

Addon Ember Node
6.x >= 3.28 >= 14.x
5.x >= 3.28 >= 12.x
4.x <= 3.28 >= 12.x

Features

No observers were used nor harmed while developing and testing this addon.

  • Lazily computed validations
  • Ruby on rails inspired validators
  • Support for Ember Data Models, Objects, Components, Services, etc.
  • Support for nested models and objects
  • Synchronous and asynchronous support
  • Easily integrated with Ember Data
  • No observers. Seriously... there are none. Like absolutely zero....
  • Custom validators
  • I18n support
  • Debounceable validations
  • Warning validations

Introduction to Ember CP Validations

You can also learn more by watching this Global Ember Meetup talk:

Introduction to ember-cp-validations

Installation

ember install ember-cp-validations

Upgrading to 4.x

If you are upgrading from 3.x to 4.x, please checkout the upgrading documentation.

Helpful Links

Looking for help?

ember-cp-validations's People

Contributors

aaronbhansen avatar artemgurzhii avatar blimmer avatar cibernox avatar danielspaniel avatar dhaulagiri avatar efx avatar fsmanuel avatar greenkeeper[bot] avatar greenkeeperio-bot avatar indr avatar jackellis avatar jakesjews avatar jasonmit avatar jrjohnson avatar kepek avatar locks avatar lorcan avatar luxzeitlos avatar mansona avatar marcoumpierrez avatar melsumner avatar mike-north avatar nullvoxpopuli avatar offirgolan avatar patsy-issa avatar rwjblue avatar samselikoff avatar stefanpenner avatar turbo87 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

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

ember-cp-validations's Issues

isInvalid helper

Many times, a button is disabled until the model is valid. It would be nice to have an isInvalid: Ember.computed.not('isValid') on a validated object.

number Validator - allowBlank/allowString and zero length value

I have a number validator that allows blanks and allows strings, but when there's a zero length value an error message displays. It doesn't appear that it allows blanks. Below is my validator with options:

const blankGte0 = validator('number', {
  gte: 0,
  allowBlank: true,
  allowString: true,
  count() {
    return this.options.gte;
  }
});

Applying multiple separate regex validations possible?

I have 2 different regex validation options available as utils for my password field. The user can use one or both validations in the model. In the example below we want to have special characters and numbers in the password. I am seeing weird behaviour when applying multiple regex like this -

validationsPassword: [
        validator('presence', true),
        //problem combining regex checks
        validator('format', {
            regex: /(?=.*[!@#$%\^&*)(+=._-])/g,
            message: "Must contain special characters"
            }),
        validator('format', {
            regex: /\d/g,
            message: "Must contain digits"
            }),
        validator('length', {min: 6})
    ]

When I put in 'a4$' for example in the field, after typing the '$', it shows the Must contain digits error. After entering another number, it says 'The field is invalid'
How can I apply these regex validators separately, on the same field?

Tabbing through fields sets off validation unexpectedly

When viewing the demo, it appears that tabbing through the fields will set off the validation immediately on the field that the cursor is entering. I would expect it to show up on the field that the cursor is leaving, but not the field the cursor is entering. This does not occur when using the mouse to enter a field.

Demo here: http://quick.as/X6QLFp21B

Decoupled i18n Addons

As discussed in #43 and suggested by @jasonmit, we have decided that it would be better to completely decouple the i18n solutions and leave the work to separate addons that will extend the message validator with the logic necessary.

  • Support for Ember-Intl
  • Support for Ember-I18n
  • Support for attributeDescription

Once these two will be supported we can issue a v2.0 release.

Email validation too restrictive

The current email regex rejects gmail style email aliases (eg [email protected]).

This can definitely be supported using a custom regex, but I wanted to offer up this alias scenario for consideration as I think it's a pretty common use case.

I think you could go much further if interested. The specific supported syntax for the local-part of email addresses are a bit tough to divine from the various RFCs, but according to RFC3696 the following are also valid characters: ! # $ % & ' * + - / = ? ^ _ . { | } ~`.

I'd be happy to provide a PR if there's interest.

Presence validation fails on relationships

If you have a belongsTo or hasMany and simply want to check that something has been set on the record, but the models on the other side of the relationship don't have validations to run, it makes sense to use a presence validator on that attribute. Unfortunately, if you're using Ember-Data (for example), the relationship actually creates a "fulfilled" model that has null content until an actual record is set on that relationship. The presence validator naively checks and sees that there is an object there, and returns true to indicate it's vaild, when really it is not. Thoughts?

attributeDescription should be per-field, not per-validator

It is burdensome to pass attributeDescription to every validator of a field:

const Validations = buildValidations({
  name: [
    validator('presence', {
      presence: true,
      attributeDescription: 'Course name (language)'
    }),
    validator('length', {
      min: 1,
      attributeDescription: 'Course name (language)'
    }),
    validator('no-whitespace-around', {
      attributeDescription: 'Course name (language)'
    })
  ]
});

It is obvious that conceptually attributeDescription is an entity that belongs to the whole field and should be shared among all validators.

I suggest the following API:

/**
 * Top level method that will ultimately return a mixin with all CP validations
 * @param  {Object} validations  Validation rules
 * @param  {Object} commonOptions  Options to be includd into every validator unless defined explicitly
 * @return {Ember.Mixin}
 */
export default function buildValidations(validations) {

which would drastically simplify the above example:

const Validations = buildValidations({
  name: [
    validator('presence', true),
    validator('length', { min: 1 }),
    validator('no-whitespace-around')
  ]
},
{
  attributeDescription: 'Course name (language)'
});

Further examples for manual validation

I'm exploring ember-cp-validations for form validation in my Ember app. Our use case is similar to your demo:

  • no validation message to be shown at first
  • only validate each field after focus-out

I'm able to use the methods like isValid and isDirty to partially solve the problem, but these are bound values, and show up as soon as the user starts typing in a field.

How do I prevent the validations being run, until I do something like validateSync()?

Ideally, I'd love to see the code for the demo app, and have it added to the docs as a real-world example.

Thanks for all your work on the project.

Allow message on custom validators to be set via options

For all the validators, except ones that are custom, the message is set on the options object. It would be handy if this was available for custom validators as well:

var Validations = buildValidations({
  hello: [
    validator(function(value) {
      return false;
    }, { message: 'Sorry, this greeting will never pass' }),

    validator('length', {
      is: 25,
      message: 'The greeting should be 25 characters long'
    })
  ]
});

The function passed could return true or false, with the message still passed in via the options and used when the case is false. This would help where people use quick boolean helpers for the function.

Debounced Validations

In regards to #57, it might be useful from a UX perspective to have an option to debounce validations. This would also be needed for custom ajax dependent validations. This will definitely need to be explored a little more but a simple definition can look something like this:

var Validations = buildValidations({
  foot: validator('custom-ajax', {
    debounce: 500
  })
});

@blimmer @stefanpenner any thoughts?

v-get can't be used inside {{if}}

 <div class="form-group {{if (v-get model property 'isInvalid') 'has-error' }}">
  <label for="email">{{label}}</label>
  {{input value=(mut (get model property)) placeholder=placeholder class='form-control' type=type}}
  {{#if (v-get model property 'isInvalid')}}
    <div class="error">
      {{v-get model property 'message'}}
    </div>
  {{/if}}
</div>

The (v-get) inside the class="" (first line) isn't handled properly, resulting in "A helper named 'v-get' could not be found"

The other cases (of course) work fine.

Clear error messages

In reference to #80

There should be a way to clear errors with the ability to clear errors for a specific type(s).

  • clearErrors()
  • clearErrors(['presence', 'length'])

QUnit-flavor tests generated for non qunit users

At the very least, if they're not using qunit, we should warn and not generate a test.

import Ember from 'ember';
import { moduleFor, test }
from 'ember-qunit';

moduleFor('validator:better-confirmation', 'Unit | Validator | better-confirmation', {
  needs: ['validator:messages']
});

test('it works', function(assert) {
  var validator = this.subject();
  assert.ok(validator);
});

Changelog

We should provide a changelog either in the release notes or a CHANGELOG.md file.

Documentation doesn't explain anything about belongs-to or has-many

Right now, the documentation says that you can validate associations using validator('belongs-to'), but this does not seem to produce any validation error messages under any circumstances—the association is not checked for presence, and the association's validation messages do not bubble up to the parent object's validation messages.

How does it work? What does it do? :)

checking an arbitrary (Ember.)Object while in a test

I am trying to do some custom validation for objects pulled in while the test environment runs (ember-qunit). It's built like this:

module('test arbitrary object', {
  beforeEach: function () {
    this.application = startApp();
    this.container = this.application.__container__;
  }
});

test('it works', function(assert) {
  // make a validation mixin
  const Validations = buildValidations({
    a: [validator('presence', true)]
  });
  /* theObject usually comes from somewhere else, this is just for illustration */
  const theObject = Ember.Object.extend(Validations, {
    a: 5
  }).create();
  // validate, check, whatever
});

I still get <(unknown mixin):ember230> is missing a container. and don't know how to properly pass in the container in this case (but I do have one, it's in this.container in the test function scope). Is it at all possible?

Introduction to ember-cp-validations on Global Ember Meetup?

Would you be interested in giving an Introduction to ember-cp-validations lightning talk at one of the future Global Ember Meetups?

The talk is usually 15 minutes long and answers the following questions:

  1. What problem is the addon trying to solve?
  2. How to get started?
  3. How should it be used?
  4. What should person be aware of?

We'll produce a video that you can link to in your README. You can see existing videos here https://vimeo.com/album/3607049

What do you think?

Documenting `createErrorMessage` and allowing custom message templates?

I found assembling custom validator messages to be burdensome. I decided to have a look how it's done in default validators and discovered that a nice helper createErrorMessage is used.

I ended up doing this:

import Ember from 'ember';
import BaseValidator from 'ember-cp-validations/validators/base';

// Monkey-patching the `messages` object
import messages from 'bealang-frontend-ember/validators/messages';
messages.noWhitespaceAround = 'should not have whitespace at the beginning or end'

export default BaseValidator.extend({
  validate(value, options, model, attribute) {
    if (value.length === value.trim().length) {
      return true;
    }

    // Using the secret helepr
    return this.createErrorMessage('noWhitespaceAround', options, value);
  }
});

Suggestions:

  1. createErrorMessage should be documented in the readmy and not hidden from the public. ^_^
  2. Should be able to extend messages gracefully in a way that prevents from accidentally overwriting existing messages (but allows explicit overwriting).

Confirmation validation behavior causes strange UX

it's strange to me that there's a validation error message before the user even starts typing the confirmation.

For example, consider a password reset form:

  • The user gets here and needs to fill out their password and do a confirmation
  • The types their password the first time
  • They see a message that the passwords don't match, but they haven't even entered the confirmation yet

For example:

What do you think about applying the confirmation to the actual ${foo}Confirmation property itself instead of the ${foo} property? That way you can associate the error with the confirmation field if it's wrong.

Validation in components only

Using the example code I am trying to create a component that does all it's own validation, but can't quite get it right.
In reality I am looking at creating some input boxes that have the validation baked in to them where they take a property and not a model.

Is this possible, and can you provide any kind of example on how this may work?

Thanks in advance.

Validation without messages

Is it possible to have validations done without a message being included? In this case the messages array would not contain a value for the invalid property.

i18n message example

Spoke to @stefanpenner awhile back about this, and sticking to my word to investigate it.

Will poke at it at some point this week to see how we'll be able to leverage the services of ember-intl || ember-i18n to resolve translation keys and handle formatting with params.

Documentation doesn't mention `needs` for unit tests

While writing a unit test for an ember-data model with validations, I had to add needs: ['validator:presence'] to the unit test, which isn't documented anywhere that I can find. Maybe a good thing to mention?

Needs Documentation

This is just a comprehensive todo list on what needs to be documented or just needs more extensive documentation.

  • belongsTo validator
  • hasMany validator
  • createErrorMessage in BaseValidator
  • needs in unit testing
  • Better v-get helper
  • Ember.Object container dependency

validator option `if` is not documented anywhere

Even though it is possible to add a condition to validators using the if option, it is not documented anywhere. For example:

var Validations = buildValidations({
  title: validator('presence', {
    presence: true,
    "if": "enabled",
    attributeDescription: 'Title',
    message: 'must be provided when enabled'
});

This validator does actually use the enabled property as a condition to enable or disable this validation, and the validations.messages property includes the error message only if enabled is true, but the if option is not documented anywhere in the ember-cp-validations documentation.

v-get helper

Create a general helper to access properties on the validation object.

  • (v-get model 'username' 'isValid')
  • (v-get model 'isInvalid')
  • {{v-get model 'username' 'message'}}
  • {{#each (v-get model 'messages') as |message|}} {{/each}}

Extra work done in validation-results-collection.js?

Are we doing extra work by pulling both .messages and .message from the validation here?

It seems like since .message is always an alias to messages.firstObject we shouldn't need to grab both. It's working currently because we flatten and uniq, but if we don't need to grab both, seems like we should always just have .messages.

Improve Demo with simple visited-input component

While we're discussing a forms library, we should improve the UX of the demo with a visited-input or something that tracks when to show the validation errors. I have one that I could clean up and open-source, and I know that @jimmay5469 said that he has one, too.

This will provide a nice interim solution for folks.

Unable to use validations on Ember.Object

Hello everyone,

This library is amazing! Unfortunately, and maybe I'm doing something horrible here, I'm unable to make this work with an Ember.Object. I keep getting an error from validations-factory.js:288 that reads: "Uncaught TypeError: <(unknown mixin):ember490> is missing a container.

Now, I will admit, I'm trying to maybe be too clever with this, but even when I tighten up the following code to JUST be the buildValidations output I still get the error. I apologize for all the code in here, I know its a lot to read, but I didn't know how else to communicate my issue.

I'm using the following code (I wanted to provide an Ember Twiddle but I couldn't figure out how to put an addon in there):

app/mixins/lazierValidationMixin.js

  import Ember from 'ember';

  var computed = Ember.computed;
  export default Ember.Mixin.create({
     displayValidation: false,
     vattrs: computed.alias('validations.attrs'),
     vattrsAreValid: computed.and('validations.isValid', 'displayValidation'),
     vattrsAreInvalid: computed.and('validations.isInvalid', 'displayValidation')
  });

app/pods/login/loginValidations.js

  import Ember from 'ember';
  import { validator, buildValidations } from 'ember-cp-validations';
  import lazierValidations from 'cookbook/mixins/lazierValidationMixin';

  var validations = buildValidations({
     username: validator('presence', true),
     password: validator('presence', true)
  }).reopen(lazierValidations);

  var computed = Ember.computed;
  export default validations.reopen({
     invalidUsername: computed.and('displayValidation', 'validations.attrs.username.isInvalid'),
     invalidPassword: computed.and('displayValidation', 'validations.attrs.password.isInvalid')
  });

app/pods/login/model.js

  import Ember from 'ember';
  import validations from './loginValidations';

  export default Ember.Object.extend(validations, {
     username: null,
     password: null
  });

Note that if I do this on a controller, this works just fine. Here's a sample controller and template (using Foundation but whatever). When I try to return my above model from a route with model.create() and then change all the below bindings to prefix 'model.whatever' it doesn't work.

app/pods/login/controller.js

  import Ember from 'ember';
  import validations from './loginValidations';

  var { get, set } = Ember;

  export default Ember.Controller.extend(validations, {
     actions: {
        submitLogin() {
           if (get(this, 'validations.isValid')) {
              alert("Go!");
           }
           else {
              set(this, 'displayValidation', true);
           }
        }
     }
  });

app/pods/login/template.hbs

  <h1>Login</h1>
  <form>
     <div class="form-item">
        <label for='username'>Username</label>
        {{input type='text' id='username' value=username class=(ifinvalidUsername 'invalid')}}
        <span class='validation-error'>{{vattrs.username.message}}</span>
     </div>

     <div class="form-item">
        <label for='password'>Password</label>
        {{input type='password' id='password' value=password class=(ifinvalidPassword 'invalid')}}
        <span class='validation-error'>{{vattrs.password.message}}</span>
     </div>

     <button type="button" {{action 'submitLogin'}} disabled={{vattrsAreInvalid}}>Login</button>
  </form>

[Question] Using a debounce for a promise-based validation

I have a validation that makes a GET request to my server to check if a resource already exists in the system. What is the best approach for a debounce? I don't want to make a zillion requests to my API. I tried a few things to no avail. Maybe the debounce logic should just live outside the scope of the validation? To me it feels like I should handle this where the actual request occurs. Hopefully someone can point me in the right direction, thanks!

import Ember from 'ember';
import BaseValidator from 'ember-cp-validations/validators/base';

const { isPresent } = Ember;

export default BaseValidator.extend({
  validate(value, options, _model, attribute) {
    const adapter = this.container.lookup('adapter:unique-resource');
    return adapter.checkUniqueness(attribute, value, options.endpoint).then(function () {
      return true;
    }).catch(() => {
      const errorMessage = isPresent(options.message) ? options.message : this._defaultMessage(attribute);
      return this.createErrorMessage('invalid', value, { message: errorMessage });
    });
  },

  _defaultMessage(attribute) {
    return `${attribute} has already been taken`;
  }
});

Don't work with Component

var Validations = buildValidations({
  username: [
    validator('presence', true),
    validator('length', { min: 5 })
  ],
  identification: [
    validator('presence', true),
    validator('format', { type: 'email' })
  ],
  password: [
    validator('presence', true),
    validator('length', {
      min: 8,
      max: 26
    })
  ]
});

export default Ember.Component.extend(Validations, {
//...
});

Can't access from template through validations.attrs.username (for instance)...

Lodash isn't available after installing the package

I get this error:

Error while processing route: forgot.index Could not find module `lodash/array` imported from `ember-cp-validations/utils/validations-factory` Error: Could not find module `lodash/array` imported from `ember-cp-validations/utils/validations-factory`
    at requireFrom (http://localhost:4200/assets/vendor.js:145:13)
    at reify (http://localhost:4200/assets/vendor.js:132:22)
    at mod.state (http://localhost:4200/assets/vendor.js:175:17)
    at tryFinally (http://localhost:4200/assets/vendor.js:56:14)
    at requireModule (http://localhost:4200/assets/vendor.js:174:5)
    at requireFrom (http://localhost:4200/assets/vendor.js:147:12)
    at reify (http://localhost:4200/assets/vendor.js:132:22)
    at mod.state (http://localhost:4200/assets/vendor.js:175:17)
    at tryFinally (http://localhost:4200/assets/vendor.js:56:14)
    at requireModule (http://localhost:4200/assets/vendor.js:174:5)

Validations Demo include template code?

Hi there!

Would it be possible to include the code for the template in the demo when you click "inspect code"? I'd like to see the markup for that, because right now I'm having trouble displaying the errors only after the input is focused on and then again when the submit button is pressed. Alternatively, if you could point me towards the source code for the demo site on github that would be so helpful!

Thanks,

Shannon

Need a complimentary library to support form validation

As others have eluded, we need a solution to provide a better UX for displaying validations when used on a form. We don't think that this should be provided as part of this library, but there's interest in defining/developing a solution that works well with this library.

Before we start designing the solution, we want to explore the problem space with some examples ranging from simple to very complex forms.

To facilitate this discussion, I've created this repo to show running examples. Please fork and provide PRs with forms you've needed to build in the past that has been a struggle with the solutions available today.

Overall here are the parameters we're considering as part of this project:

  • not bound to one design language (e.g. bootstrap, foundation, etc.)
  • option to defer displaying validation errors until the user has somehow interacted with the form/field
  • disabling the submit button until validation passes

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.