A button is the most basic UI element you can probably think of, however
in web apps it's largely implemented as some sort of secondary-class citizen -
reacting to events properly, but not adjusting to various use cases that largely
depend on the context. For example, it is often common to use button as a simple
link instead of a form submit element, but it's also obvious it should behave
the same way (as a button!) when it's just a link - that is, appear to be pressed.
Or, perhaps, it should behave like a real button in some ways, but not others.
To understand which features of the
are applicable in which cases it's better to do an overview of those features first, then learn how to
use them, and then we can discuss situations in which those features can be applied.
While Webface.js lacks any kind of formal definition of "state", it is normally defined by component attributes, html attributes and, in particular, css classes assigned to a particular dom element.
Button has three important states it can be in:
Means a button is clickable and will publish the
clickevent if user clicks it.
Means a button is temporarily made inaccessible due to some action, typically user clicking that button. In this case, a
lockedcss class is added to the button's dom element.
You can toggle between having this state on and off with
behave("unlock"). By default, on
behave("lock"). This default behavior can be disabled by setting writing
button.set("lockable", false)(can also be done through
data-lockable="false"attribute, it will update the corresponding
ButtonComponentattribute automatically on initialization). Normally, in your css, you'd want to add styles to the
button.lockedselector, such that the button looks different from a normal one: for example has slightly less bright colors and a spinner is shown over the button, indicating that some processing is being performed.
webface_railsgem provides css styles for buttons along with the rest of the stylesheets for all of Webface.js standard components.
Suppose your button doesn't invoke any actions that require some significant time to process - such as http requests or cryptographic algorithms - and it's potentially ok (and even expected) that users click it multiple times. For instance, if you have a form to purchase tickets for an event, it is possible that buyers would want to purchase multiple tickets for different people - we cannot predict how many, so we would add a button saying "Add attendee", which would add a row of form fields that are required for each attendee. In this case, it makes no sense to lock the button because adding new form fields is done very fast. The button, of course, would not be adding the fields itself, but merely publishing theWe won't need to change anything in
clickevent, while its parent - our custom form component of some sort, would capture the event and we'll write some code that would process this event. All the while, the only thing we'd need to do is add a simple html-attribute to the button's dom element:
ButtonComponentfor this to work.
Means a button is not supposed to be clicked at all - typically because some condition, such as required form fields not being filled - is not satisfied.
This state is defined by the
disabled="disabled"to the button's dom element.
Note how the previous "Locked" state didn't have a corresponding attribute in
.lockableis a setting that affects locking the button, but not the state itself. And having the
lockedattribute is not actually necessary - we just add or remove button dom element's css class in
ButtonComponentBehaviorsto accomplish our goal. But with
disabledthere is a component attribute we can (and should) change with
To disable/enable the button, please use the component's attribute setter (instead of behaviors) like this:
If you use behaviors instead, the button may appear disabled for users, but the value of the component's attribute will remain unchanged, which may affect your code.
The click event and its handler
The most common thing people do to a button is click it (or tap it, which highly depends on one's sexual preferences). Thus, the handler for this behavior has a number of things worth discussing:
Event lock is set to the click event whenever a button is clicked
lockableattribute was previously set to
false. If button is locked, either after it was clicked or because we locked it programmatically, it will not process any further
clickevents until it is unlocked. You MUST unlock it with
ButtonComponent.behave("unlock")manually from your code when you want to be back to processing new click events again - there's currently no default event handler which does it for you (because there's no reason for it).
You can prevent browser from invoking its default handler for your button
clickevent by setting
true. This is useful in forms, for example, when you don't want to immediately submit a form, but rather validate it in the frontend and only submit that form after all validations pass. The default browser handler for the submit button, in this case, is submitting the form. We disabled this handler, while still instructing Webface.js to run our own handler code. This is so common (as buttons are mostly used in forms) that
ButtonComponentdefaults to preventing native browser event handler for the
clickevent for all of its instances. However, it is also desirable to enable default browser handler when a button acts as a link. It can be done by adding an appropriate html-attribute:
If you're using webface_rails, there's a special helper to generate buttons that act as links:
button_link. See Ruby On Rails integration / Standard components views for more info.
If you're not using webface_rails, don't forget to set
data-prevent-native-click-event="false"on the submit buttons (if that's indeed what you want). TODO: perhaps the default attribute setting should be changed to
data-prevent-naive-click-event="false"to avoid confusion, while setting the attribute value to
truefor all buttons that are not links in webface_rails.