Image Credit

User Interaction in Willow

Maximiliano Tabacman
mercap-blog
Published in
5 min readJan 28, 2021

--

This is the fifth post on our series on how to use Willow to create web applications, where we will cover user interaction.

The series so far:
1) Introducing Willow
2) Your first Willow application
3) Rendering content in Willow
4) Component Suppliers in Willow
5) User Interaction in Willow (this post!)
6) Dynamic content loading in Willow

What can be done?

Whenever someone clicks on a part of your application, changes the content of a field, passes over an image, etc. you might want to have it respond with feedback for the user or register information in your server. Willow wraps Javascript events using JQuery, so you can use it to configure what to do on click, change, focus and a lot more.

Interactive objects allow the on trigger collaboration to refer to the most common interaction on them. This means click for buttons and links, change of selection for combo boxes, radio buttons and check boxes, editing values for text fields.

For example, to notify the server that the user edited the field in our To Do example we would send:

field on trigger serverDo: [ self halt: 'Edited by user!' ]

So based on the code up to previous post, we’ll update ToDoApplication>>#renderInputOn: to:

renderInputOn: aCanvas
| field |
field := self componentSupplier singleLineTextFieldApplying:
[ :theField | theField setPlaceholderTo: 'Write your task' ].
field on trigger serverDo: [ self halt: 'Edited by user!' ].
aCanvas render: field

How do I obtain the values chosen by the user?

Whenever we define an interaction that notifies the server (like serverDo:) for a Willow component, triggering it will also ensure the server receives its updated value. Otherwise we can explicitly ask for the component contents to be sent to the server by sending serializeIt. For a complete list of the interactions that notify the server see the documentation on Github.

Each component has its own protocol to obtain the current value. Fields respond to model, while single selections respond to currentSelection. You are encouraged to explore the protocol for each component, which is outside the scope of the current post.

To open an inspector on the content indicated by the user, we can change our method to:

renderInputOn: aCanvas
| field |
field := self componentSupplier singleLineTextFieldApplying:
[ :theField | theField setPlaceholderTo: 'Write your task' ].
field on trigger serverDo: [ field model inspect ].
aCanvas render: field

Note that the field is triggered when a change is detected; this means when the user leaves the field (clicks on another component, tabulates to the next component, etc). This is the default behavior for fields and is equivalent to sending on change. To trigger after every character is entered, we should use on keyUp instead:

renderInputOn: aCanvas
| field |
field := self componentSupplier singleLineTextFieldApplying:
[ :theField | theField setPlaceholderTo: 'Write your task' ].
field on keyUp serverDo: [ field model inspect ].
aCanvas render: field

Willow includes by default protocol for change, click, key up and mouse over, but you can also send on eventNamed: #yourEvent, as can be seen by exploring EventInterpreterDispatcherBehavior.

How do I send new content to the user?

Willow offers a wide range of commands that can be chained after on [trigger|click|change|…], where each will automatically add the necessary Javascript to be executed and the correct moment. The whole range of commands available are the methods in the Configuring* categories in WebInteractionInterpreterBehavior.

Apart from generating an effect on the server, an interactive component can either do something before contacting the server, or after it has completed the request and obtained a response.

There are interactions that will occur before notifying the server, like enabling/disabling a component or changing its CSS classes. Depending on your intention, it may be all you want to do, and the server won’t even be bothered with it.

We could, for example, define that our button is to be disabled when the application starts, and we’ll enable it only after the field changes its contents:

addTaskButton
^ self componentSupplier asynchronicButtonLabeled: 'Click me'
applying: [ :theButton | theButton beDisabled ]
renderInputOn: aCanvas enabling: aButton
| field |
field := self componentSupplier singleLineTextFieldApplying:
[ :theField | theField setPlaceholderTo: 'Write your task' ].
field on trigger enable: aButton.
aCanvas render: field
contentView
^ [ :canvas | | button |
button := self addTaskButton.
self renderTasksOn: canvas;
renderInputOn: canvas enabling: button.
canvas render: button ]

Other interactions will probably depend on doing something on the server first, like focusing on a component, opening or closing a dialog, or refreshing some part of your application.

Let’s simulate server processing when the button is clicked, by obtaining a text in the Pharo image, then using it to fill the text field:

taskDescriptionField
^ self componentSupplier singleLineTextFieldApplying:
[ :theField | theField setPlaceholderTo: 'Write your task' ]
contentView
^ [ :canvas | | textField button |
textField := self taskDescriptionField.
button := self addTaskButton.
textField on trigger enable: button.
button on trigger
setValueTo: [ UIManager default textEntry:
'Write what you want to see on the text field' ]
withoutTriggeringChangeOnComponentWithId:
( textField identifierOn: canvas ).
self renderTasksOn: canvas.
canvas render: textField;
render: button ]

As can be seen from the previous examples, once the interaction between components starts to increase, methods will get longer. This is a good indication that we should begin extracting parts of the behavior into separate methods.

What else can Willow do?

The previous sections have presented a small glimpse of what can be achieved using the interaction affordances in Willow. The main idea is to define small components that interact only with other small components, keeping the application manageable, and reserving whole page changes only for specific cases like user sign in. This is achieved using AJAX calls and aiming to develop a single page application.
Apart from navigating the protocol of all the objects mentioned, you are encouraged to review the documentation available on Github.

What comes next?

Now that we have seen how to define the style and interactions of the components, the next posts will focus on how to implement the main functionality of our ToDo application: adding tasks.

--

--