Page MenuHomePhabricator

Implement ToggleSwitchInputWidget
Open, MediumPublic


I was surprised to see that when I added a ToggleSwitchWidget to a form (replacing a checkbox) that when I submitted the form it did not behave as a checkbox. In fact if I inspect the element I see no evidence of a form input. As a result I'm having to keep a hidden element around and update its value on every change event.

As far as I'm concerned this element should be interchangeable with the CheckboxWidget - on mobile web we want to use this instead of a checkbox, but still support NON-JS use cases.

I realise the primary use case for this is asynchronous saving, but it should also support synchronous saving.

Event Timeline

Jdlrobson triaged this task as Medium priority.Dec 8 2017, 8:49 PM
Jdlrobson created this task.

The convention is that only widgets that are subclasses of InputWidget (and whose names end in 'InputWidget') are compatible with HTML <form>s.

Note that even if we were to ignore this convention, ToggleSwitchWidget can not be changed to be a drop-in replacement for CheckboxInputWidget – they have incompatible APIs (the #setValue and #getValue methods do different things in them).

So, my first thought is that this could be implemented as a new widget, ToggleSwitchInputWidget or something, that would synchronize a pretty toggle with an invisible <input type=checkbox>. The new widget would extend InputWidget (or maybe it would extend CheckboxInputWidget, I'm not sure what would make implementation easier).

My first idea was to use a ToggleSwitchWidget internally, and synchronize it explicitly with the invisible checkbox, similar to how DropdownInputWidget synchronizes a DropdownWidget with an invisible <select>. But this wouldn't be possible in the non-JS (PHP) version, obviously. So at least for PHP you might have to use the same approach as CheckboxInputWidget, and then copy-paste and tweak the toggle styles to use the :checked selector instead of the .oo-ui-toggleWidget-off/-on classes. And once you do that it might be easier to do the same thing for JS…

This will probably be quite boring work, but it should be easy, even for a new contributor. (The only difficult part is figuring out where the newly added widget's files have to be listed for it to be included in the build – you can steal that from older commits that added widgets, e.g. 376959a58f2bc2ed0204cdaf059092fdb201a4a6.) @Jdlrobson Do you want to do this, or do you want to convince someone from your team to do this, so that I stop being a bottleneck for such things? :)

Thanks for the detailed investigation @matmarex. We're probably going to work around it for the time being. I think a hidden input would be the most straightforward thing to do here. Any reason ToggleSwitchWidget could not have one and store its value there?

That isn't possible for non-JS, and you said that's a requirement.

Note that using a <input type=hidden> instead of hidden <input type=checkbox> is actually more work, if you want it to be consistent with how checkboxes behave. For example, to match how form submission of checkboxes works, you'd have to make it disabled when the fake checkbox/toggle is unselected, and as enabled when it's selected.

Adding a <input> (of whichever kind) to ToggleSwitchWidget would require you to write code to handle name, value, disabled, etc., for it. It's better to extend InputWidget so that you don't have to duplicate this.

It makes a lot of sense to implement a ToggleSwitchInputWidget.

Volker_E renamed this task from ToggleSwitchWidget should be compatible with forms to Implement ToggleSwitchInputWidget.Dec 15 2017, 2:45 AM
Volker_E updated the task description. (Show Details)

No, to be clearer what we are doing is creating a form with a Checkbox widget. When client-js class is added we make it visibility: hidden. With JavaScript we then replace the checkbox widget with a ToggleSwitchWidget. A ToggleSwitch behaves differently from a Checkbox - when clicked it is expected to save automatically. With a checkbox it is expected to be followed by a button click.

The asynchronous behaviour is where we are hitting the problem. The saving should be the same - it's a binary value on or off. The problem we are hitting is our asynchronous saving is done via a form submit of the form itself (currently we're refreshing the page, but equally we could target a hidden iframe (we just never got round to that)). This is necessary due to the way the mobile beta needs to create a session on the server. There's no API for that right now, which would be the alternative.

We may also want to make the ToggleSwitch behave like a checkbox without JS but that's probably out of scope right now.