I love this way of thinking about web application development, and we take a similar approach on my team at work.
There are problems though.
> When a form is "editable" … I just have that plus button add a query param and use HTTP GET to get a new version of the form with that field added.
I've done this kind of thing before, but the sticking point for me was how this interacted with the history API. If a user visits a form, adds a new field with a GET request, and then uses the browser's back button, where do they end up? Where would they expect to be?
Instead of taking this approach, in some places we've generated a template on the server which matches the inputs that should exist in the form and then used a DOMParser to parse the template from a string.
Here's an example.
;(function() {
var parser = new DOMParser();
var ol = document.getElementById(#{theId});
function addRow() {
var doc = parser.parseFromString(#{blankDateInput}, 'text/html');
var li = document.createElement('li');
var dateInput = doc.querySelector('.date-input');
li.appendChild(dateInput);
ol.appendChild(li);
dateInput.querySelector('input').focus();
}
document.getElementById(#{addRow}).addEventListener('click', addRow);
})();
---
An alternative approach is to just generate more inputs than the user will actually need, and only show the first one. The "button" to add a new field is actually a label connected to a hidden checkbox, and you use a combination of sibling selectors and the :checked pseudo-selector in CSS to show the next input.
You can use the state of each field's adjacent checkbox to decide whether or not the value in the field should be parsed on the server.
> If a user visits a form, adds a new field with a GET request, and then uses the browser's back button, where do they end up? Where would they expect to be?
They end up at the page that they were before, with the state that was there before, as a back button should do.
Bonus, they can share the url with anyone and exactly the same form will be displayed.
I thought it was clear from my comment that I'm mindful specifically of not creating unexpected navigation behaviour, as is so common with SPA implementations.
Yes, developers should not mess with the history API, and the back button should work as expected. And, a user navigating back and arriving at the same form they were previously viewing minus one input is probably surprising behaviour.
Is it, though? Adding another sibling to an existing form element is pretty much like hitting RETURN in a text document for a new line or paragraph or list element. What would users expect, when they had opened a new line/paragraph/list element and hit CTRL/Command+Z for "Undo"? I guess, most would expect the state just before opening that new element.
(I'd even go as far as to call any alternatives confusing, like reverting the last edit in the previous paragraph, but having the empty new element still hanging around, or progressing multiple state changes back, at once, which should be pretty unexpected. Personally, I'd deem it highly annoying, if an application wouldn't allow me to revert this expansion step, without implicitly changing any previous edits, as well. Mind that adding an element is pretty much a modal barrier in the editing process and not only crucially different from editing text, but also separates editing tasks into "natural" groups. Which is also why we use such grouped actions and elements in form-centric workflows, in the first place.)
As in, "back to the state before the last interaction", which is pretty well defined.
(If there are clearly grouped interaction with transitions, this may be "back to the state, the last grouped interaction was finished and the current one opened.")
If you are interacting with a modern log-in box, where there is a first state to input the user name or account ID and then a transition to a separate state presenting a password input for this account. You hit the back-button. What do you expect? The box switching back to the input of the account ID, or leaving that site altogether to wherever you came from (e.g., Google)? I guess, most would expect the former, because there is change of state and a transition. I think, adding another sibling, thus changing the form on our own account, is such a change of state, as well. (In other words, we may want to revert this step, but we do not necessarily expect CTRL/Command+Z to work in this context, like it does for a "normal" editing task. But we may expect the back-button to work. Not to the least, because we had to press an action button in order to arrive at the present state.)
Moreover, this is pretty much how forms have worked for the first 20 years of the Web. (I.e., the browser stores a snapshot of the state of the page just before any transition or navigation event and restores this on the press of the back-button. Before there were single-page approaches, this was well defined.)
I don’t see those two ideas as equivalent, and so I don’t agree at all.
I can imagine a user seeing a page to input their email address and a subsequent page to input their password as two different pages, and so navigating back from the password input page should take you to the email input page.
I don’t think a user would expect to return to a page which models n-1 of a kind of a input when navigating back from a page which models n of a kind of input because conceptually they are the same thing.
They are not to the least conceptually the same thing: this is the form you customized by interacting with an action button. You expect this to change the state, and you do this either for a purpose, or by accident (in which case you may want to revert this, as you may fear that you've just broken the process.)
There are problems though.
> When a form is "editable" … I just have that plus button add a query param and use HTTP GET to get a new version of the form with that field added.
I've done this kind of thing before, but the sticking point for me was how this interacted with the history API. If a user visits a form, adds a new field with a GET request, and then uses the browser's back button, where do they end up? Where would they expect to be?
Instead of taking this approach, in some places we've generated a template on the server which matches the inputs that should exist in the form and then used a DOMParser to parse the template from a string.
Here's an example.
---An alternative approach is to just generate more inputs than the user will actually need, and only show the first one. The "button" to add a new field is actually a label connected to a hidden checkbox, and you use a combination of sibling selectors and the :checked pseudo-selector in CSS to show the next input.
You can use the state of each field's adjacent checkbox to decide whether or not the value in the field should be parsed on the server.