I am currently building a fairly complex form with a lot of conditional logic. by that I mean, when users check one option, 1 or more others maybe revealed or hidden - you've probably seen it many times before..
Using Ractive's mustache templates and many {{#if }}
statements I have created the form, but the logic for validation and submission needs improvement. I need to enable the submit button only when all 'visible' fields are valid, so I have concluded that each field needs an isInUse
property as well as isValid
, see below for an example:
data: {
foo: {
isValid: false,
isInUse: false,
value: ''
}
}
The reason for this is that a field could be made visible
but then an option could hide it & it might still have a value that the user does not need to submit.
I have also determined that the only reliable way to change the isInUse
property is to create a function in my data that can be accessed from my template, like so:
data: {
foo: {
isValid: false,
isInUse: false,
value: ''
},
isInUse: function (keypath, bool) {
ractive.set(keypath, bool);
}
}
which is used in my templates like so:
{{#if choice.email}}
{{ isInUse('validate.email.isInUse', true) }}
{{ isInUse('validate.phone.isInUse', false) }}
<label for="email">Email</label>
<input type="text" id="email" value="{{validate.email.value}}">
{{/if}}
This means I am able to change the value on the template-side.. which means I can check if each field is in use and valid.. now this is where I am questioning the implementation, is this a good idea?
I have created a simple version of the form on jsbin (which completely works with validation & submission), see here: http://jsbin.com/wasoxa/2/edit?html,js,output but my form is much more complex so I'd like to find a graceful way of handling all of this.
Calling
isInUse
from within the template is a very creative solution, but unfortunately very likely to break!You should think of expressions in templates as being read-only - you can call a function within an expression, but only to get its value, never for side-effects such as setting another value (the one possible exception being to log output for debugging). The reason is that you're not in direct control of when the function is called - Ractive handles that on your behalf - so you can get unexpected results. In the example above, changing
choice.email
fromtrue
tofalse
won't have the desired effect.You probably want computed properties. These can be read inside the template just like regular properties, except that their value depends on other data (or other computed properties):
Whenever
foo
changes,doubleFoo
knows (because we calledthis.get('foo')
inside its definition) that it should recompute itself. You can use computed values just like you'd use any other value - e.g.ractive.observe('doubleFoo',doSomething)
.This can be useful for validation: