Bacon.js combine properties with .and() only if prop === true

159 Views Asked by At

I've picked up Bacon.js recently and doing some UI with it in which I only enable a 'Sign up' button if the requirements are met, one of them is check that the username is valid.

// Returns true or string with invalid reason
var isUsernameValid = username
    .map(function(value) {
        if(value.length < 4) {
            return 'Must be 4 characters at least';
        }

        if(!config.patterns['username'].test(value)) {
            return 'Can only have letters, numbers, periods, or underscores';
        }

        return true;
    });

It either returns true or why the username is invalid.

Later I combine all the results with this:

password.and(username).and(isUsernameValid)
    .not().assign($(view['signup-submit']), 'toggleClass', 'disabled');

Username and password are only true when there's input, but since isUsernameValid always returns a truthy value the buttons ends up being incorrectly enabled.

Is there a better way to return errors or combine properties by passing a function?

I thought of declaring another stream/property to return if the value === true but I'm trying to avoid that.

2

There are 2 best solutions below

0
On BEST ANSWER

The issue was because your truthy value includes both valid and invalid cases. That function never returns falsy values. How about seperating invalid and valid into truthy and falsy values?

var isUsernameInvalid = username
  .map(function(value) {
    if(value.length < 4) {
      return 'Must be 4 characters at least';
    }

    if(!config.patterns['username'].test(value)) {
      return 'Can only have letters, numbers, periods, or underscores';
    }

    return false;
});

Then, without much change to the original code

password.and(username).and(isUsernameInvalid.not())
  .not().assign($(view['signup-submit']), 'toggleClass', 'disabled');
1
On

I would do it like this:

var isUsernameLongEnough = username.map(function(value) {
  return value.length >= 4
})
var usernameHasCorrectCharacters = username.map(function(value) {
  return config.patterns['username'].test(value)
})

var isUsernameValid = isUsernameLongEnough.and(usernameHasCorrectCharacters)

password.and(username).and(isUsernameValid)
    .not().assign($(view['signup-submit']), 'toggleClass', 'disabled')

isUsernameLongEnough.not().assign($(view['error-too-short']), 'toggle')
usernameHasCorrectCharacters.not().assign($(view['error-invalid-characters']), 'toggle')

It is better to keep each function small and separate the concerns.