Patterns for handling default values for inputs

Explanation

I have recently been building wikis with tiddler-building forms. Everything makes sense to me there, except for handling of default values. There, my defaults seem to be repeated too often. I’m wondering if there are better patterns for handling them.

Sample Code

Here is a sample form, created just to demonstrate my concerns:

<div class="data-entry">
    <label>First Name:</label>
    <$edit-text tabindex=1 tiddler={{{ [[$:/temp/entry-form]] }}} field="first-name"  /> <br/><br/> 
    <label>Last Name:</label>
    <$edit-text tabindex=1 tiddler={{{ [[$:/temp/entry-form]] }}} field="last-name"  /> <br/><br/> 
    <label>Date of Birth:</label>
    <$edit-text  type="date" tabindex=1 tiddler={{{ [[$:/temp/entry-form]] }}} field="dob"/> <br/><br/>
    <label>Dwelling:</label>
    <$edit-text tabindex=1 tiddler={{{ [[$:/temp/entry-form]] }}} field="dwelling" default={{lookups!!default-dwelling}} /> <br/><br/> 
    <label>Favorite Animal:</label>
    <$select tiddler={{{ [[$:/temp/entry-form]] }}} field=animal tabindex=1 cancelPopups="yes" default="Panda">
        <$list filter="[enlist{lookups!!animals}]"  >
            <option>{{!!title}}</option>
        </$list>
    </$select> <br/> <br/>
    <label>The glass is:</label>
    <$select tiddler={{{ [[$:/temp/entry-form]] }}} field="glass" tabindex=1 cancelPopups="yes" default="white" default="half-full">
        <option>half-empty</option>
        <option selected="selected">half-full</option>
    </$select> <br/> <br/>
</div>

<$button tabindex=1 >
    <$action-sendmessage
        $message="tm-new-tiddler" 
        title= {{{ [[Person/]] [{$:/temp/entry-form!!first-name}] [[ ]] [{$:/temp/entry-form!!last-name}] +[join[]] }}}
        tags= "Person"
        first-name= {{$:/temp/entry-form!!first-name}}
        last-name= {{$:/temp/entry-form!!last-name}}
        full-name= {{{ [{$:/temp/entry-form!!first-name}] [[ ]] [{$:/temp/entry-form!!last-name}] +[join[]] }}}
        animal={{{ [{$:/temp/entry-form!!animal}!match[]else[Panda]] }}}
        glass={{{ [{$:/temp/entry-form!!glass}!match[]else[half-full]] }}}
        dwelling={{{ [{$:/temp/entry-form!!dwelling}!match[]else{lookups!!default-dwelling}] }}}
    />
    Create
</$button>

The related lookups tiddler is simply:

title: lookups
animals: Alligator Butterfly Cow Dog Elephant Frog Goat Hippo ... Yak Zebra
default-dwelling: House

You can play with this form by downloading the following and dragging the resulting file to a wiki:
EntryForm.json (2.5 KB)

The Flow

Everything works reasonably well. (I’d always love feedback on how to do things better though!)

But…

The first three fields—first-name, last-name, and dob—are simple enough; they don’t need default values. The user must enter them. At some point I’ll check out validation techniques to ensure they’re actually filled, but I don’t need it for my current work.

The next field—dwelling— is a text entry field, with a default stored in a separate data tiddler. In one real wiki, the user will be almost always accept such a default value, but needs to be able to override it every once in a while. On rare occasions (yearly), the default value itself will need to change.

The next two—animal and glass—are <$select> drop-downs; animal gets it’s list of values from a filter (here simplified to a lookup in another tiddler), and glass has just two hard-coded choices. Both have default values hard-coded in the <$select> widgets.

All of this would be fine, but then in the ActionSendMessage widget, I need to repeat these three default values.

The fields without defaults are simple enough:

        first-name= {{$:/temp/entry-form!!first-name}}

or slightly more complex as I combine entry fields in title and full-name.

But for these ones with defaults, I cannot accept the value in my temporarily tiddler aligned with the associated field. That is, I cannot do this:

       glass= {{$:/temp/entry-form!!glass}}

This is because if the user has not changed the input element, then no value would be assigned to the field in the new tiddler. So I have to check for an empty value, and assign my default value instead, which means something like this instead:

        glass={{{ [{$:/temp/entry-form!!glass}!match[]else[half-full]] }}}

The Problem

Any sort of dual-maintenance bothers me. It seems extremely likely that the default values of Panda and half-full could easily get out of sync between the two places they’re used.

The Question

Are there better patterns for doing these? I know I could use the dwelling pattern for the other two.
That would put the text itself in a single location, but it still leaves the default handling in both the input definition and the create tiddler action widget. I would love it if this was just in one place.

@EricShulman demonstrated a technique using an EventCatcher. That is definitely an improvement, but it only works when the user interacts with the control: tabbing through it or clicking on and off it. That subverts user expectations.

Another idea I’ve considered is finding a way to assign the default values to the fields of my temporary tiddler—here $:/temp/entry-form— when the entry form tiddler is rendered. That sounds like it would address most of these concerns. But I have no clue how to perform an action “when the tiddler is rendered”. Is this easy to do?

And in general, do you have other tools or techniques to solve this problem?

For the form layout I find the fieldset html tag nice, if helps fit the label in differently.

\define edit-fieldname(fieldname)
<fieldset>
   <legend>&nbsp;$fieldname$&nbsp;</legend>
   <$edit-text field="""$fieldname$""" tag=input size=40 placeholder="enter $fieldname$ value"/>
</fieldset>
\end

I have gone down a number of rabbit holes myself with forms, fields, edit and view. The whole thing can be abstracted multiple levels deep making interrelated tools that are easy to use, but the complexity of the solution goes up.

  • I will review your above example more.

I’ve been facing the same questions and here’s what I do: I provide an UI element (button or equivalent) to initialize the temp tiddler + trigger the display of the form, usually in a modal. Thus the fields initialization doesn’t happen when the form is rendered but just before, when the user opens the form. The form tiddler itself is hidden in a system tiddler so the user can’t access it without resorting to the provided UI button.

Fred

Thank you. I only did the minimum styling necessary here to demonstrate the problem. I’m reasonably competent with CSS, and can probably at some point make them look nicer.

I would probably not use <fieldset> myself here. Tiddlywiki is forcing me to at least somewhat abandon my long-term stance on using HTML as semantically as possible, but I still retain a lot of that idea. <fieldset> to me represents a grouped subset of the related fields in a form; I would not use it for every field individually. But at some point, I can figure out a prettier form if I choose; I’d certainly like, at a minimum, to get rid of those ugly <br/> tags!

Thank you. I look forward to your feedback. I used far too many words above to say it, but the question is pretty simple: how can I manage default values for fields of a tiddler-creation form in a way I don’t have to repeat myself?

I have thought of things like that. I think I may end up with some variant of this idea, because I’m pretty sure that there simply is no way to hook into TW’s flow. I recently suggested that it would be quite useful for TW to offer more hooks like $:/tag/StartupAction so that users could add actions on lifecycle events such as tiddler-save, tiddler-render, export, wiki-save and so on. That would make this problem trivial.

Thank you for the suggestion!

I wish it was. I wish this would work:

<$edit-text blah... value=thing />

Where thing is whatever you want it to be (!!field, macro, filtered-transclude…)

In the case where…

<$edit-text tiddler=my-tiddler field=my-field value=thing />

perhaps value is only used where field matches blank, meaning it’s a prescribed default.

  • I suppose this depends on if you want defaults for a set of fields in a form, or independent values for the fields on their own.

If you want to set the defaults for a whole form you can have a template tiddler you use to create the new tiddler, containing the form, or to create a temp tiddler you are using, on the way to creating the form fields.

  • When clicking new form or new tiddler you use the template with all its default values for each field.

  • If using a temp tiddler after all fields are accepted or changed you create the final tiddler containing the forms fields, or add the fields to a selected tiddler.

There are other ways to do this. The above is an approach I used, and can explain further if needed.

1 Like

:100:

But I do understand the constraints that TW is under; it’s hard to bind the value to a field and also allow my default to take hold. If I could perform an action on tiddler load, this would be trivial.

The latter is what I’m already doing. It’s not that it’s terrible, just a bit… unergonomic.

I’ll investigate the former. Thanks!

Not sure if this would help, but have you seen @twMat fieldvalueselector.

https://fieldvalueselector.tiddlyhost.com/

No, I hadn’t seen it. And while I don’t think that will help for this specific problem, I have a separate immediate use for this. Thank you very much!

@Scott_Sauyet
sorry but I think the Empty Form has an error.
The dob field for Date of Birth should be added to the code

Entry Form.json (2.1 KB)

You’re absolutely right. I don’t know how I missed that.

Of course this was throw-away code to demonstrate an issue, but I do still like to get details right. Thanks for noting it and for the fix!

1 Like

Just revisiting this thread it occured to me that default value is not a single thing.

  • One use is to simplify data entry by preloading with the most likely value
  • Another is more of a suggestion to help illustrate the kind of value
  • another what the value will be if you dont do anything in effect the lazy option. What you get if you dont think of it.
  • some defaults are there to encorage selection of a more meaningful value.
  • there are other defaults that can be provide like
    • the most recently used
    • the most commonly used

Of course in any particular case a default may be used for more than one of those reasons.

Sometimes we need to “read between the lines” but sometimes we need to “read behind the meaning of a word”

(Numbering added)

I suppose there is some logical difference between #1 and #3: whether the default is visible, or only used behind the scenes. But my personal case is a combination of these. I want to preload/preselect the default option, but allow the user to change them before saving.

#2 is generally covered by placeholder values in HTML and in TW.

(Numbering added)

I don’t quite understand what you mean by #4.

#5 speaks to what content you might choose to use for default values, but not really how they’re presented or used. You could have defaults for many reasons, including these two.

In the real-world problem that led to this question, it was definitely meant to be used for #5b. There are named buckets that are slowly filled up, and we almost always will want to list the latest bucket. But it’s remotely possible to go back to old buckets. So we’ll have a default value stored in another tiddler, that will be changed every 12 - 15 months, and we’ll use that as a default for this field.

@Scott_Sauyet
Thank you for the code, it’s very useful.

I did not use this as a dimension in my analysis.

Yes combinations would be common.

#2 Placeholders are presently only display text and do not act as a value.

If a field label is not meaningfull and example values not visible people may not take any notice and leave it blank. But a default value may help. Eg sex = female rather than leaving it to peoples imagination sex = yes

#5 yes I focused on the default value not the visible selection but i thought of a select widget with the default visible and a dropdown to select other values. In some cases we may need an editor to add option.

Yes just updating a value by one in a data tiddler or if that value has a corosponding tiddler a field.

Although you could have a filter that counts each value found in the wiki and sorts by the count of uses.

This can get quite meta if we had defaults and dropdowns for selecting defaults when coding :nerd_face:

Yes, of course. Thank you.

This so far has been a text field, but it might make more sense as a dropdown: with the options sorted from newest (selected) to oldest. There would be a slight bit of maintenance to that, but as it’s less than annually, it’s probably not a big deal.

I’m already getting there!

This can be automated in the values used are in a data tiddler with the key=selected value, and the value is date last used, or if the value has a tiddler then you can test the tiddlers created, modified or by design a touch date.

I really do hope, sooner or later, to build an easy to reuse mechanism for this kind of selection.

1 Like