One application of enum types is to represent categories of objects. We will take this approach in our coding-events
application to categorize events based on their type, such as conference or meetup.
Note
The starter code for this video is found at the display-errors branch of the coding-events-demo
repo.
The final code presented in this video is found on the enums branch. As always, code along to the
videos on your own coding-events
project.
As mentioned in the previous chapter, your
display-errors
constructor might contain a small quirk. If your
constructor assigns non-sequential id
values, this is still OK!
In your models
package within coding-events
, create a new class called EventType
.
Before you finish entering the name of your file, select the Enum
option from the list of
types.
Enum type selection.
Because enum values are constants, we use Java Naming Conventions and write them in all caps. Each value is demarcated with a comma and the list is completed with a semicolon.
EventType
:
6 7 8 9 10 11 12 13 | public enum EventType {
CONFERENCE,
MEETUP,
WORKSHOP,
SOCIAL;
}
|
Enums can store additional information affiliated with each value in fields. Enum fields
are treated like fields on any other type. Again, because enum values are constants, fields
should be final
variables, since they will not change.
To add a displayName
field to EventType
, we declare the field, add a constructor, and
tack on a getter method:
13 14 15 16 17 18 19 20 21 | private final String displayName;
EventType(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
|
To define the display name for each of the EventType
values, we can call the constructor we
just wrote like this:
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public enum EventType {
CONFERENCE("Conference"),
MEETUP("Meetup"),
WORKSHOP("Workshop"),
SOCIAL("Social");
private final String displayName;
EventType(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
}
|
Other objects can have enum type properties. To add an EventType
property to our model Event
,
we create a type
field in Event
amongst the other fields declared:
25 26 27 28 29 | // other Event field declarations
private EventType type;
// Event methods
|
We’ll want to also add this field to the Event
constructor, as well as a getter and setter
method:
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | private EventType type;
public Event(String name, String description, String contactEmail, EventType type) {
this();
this.name = name;
this.description = description;
this.contactEmail = contactEmail;
this.type = type;
}
public EventType getType() {
return type;
}
public void setType(EventType type) {
this.type = type;
}
|
coding-events
uses model binding to create an Event
object. So like any other field on
the model, the controller does not necessarily need to know about the addition of Event.type
in order to create an Event
instance from a form. However, we want the user to choose from
the pre-defined event type values when creating their event. To do this, we’ll use the
controller method displayCreateEventForm
to pass those values into the view.
In EventController
:
26 27 28 29 30 31 32 | @GetMapping("create")
public String displayCreateEventForm(Model model) {
model.addAttribute("title", "Create Event");
model.addAttribute(new Event());
model.addAttribute("types", EventType.values());
return "events/create";
}
|
.values()
is a built-in static method that returns an array of values defined in
the given enum, in the order in which they have been declared.
With the template variable types
now defined, we can use our EventType
values in the view.
Select
Element¶The list of constants returned from EventType
lends itself well to a select
-type form
input. We’ll update our form so that a user will have the option to choose one of the provided
event types from a dropdown menu.
In templates/events/create.html
:
27 28 29 30 31 32 33 34 35 36 | <div class="form-group">
<label> Type
<select th:field="${event.type}">
<option th:each="type : ${types}"
th:value="${type}"
th:text="${type.displayName}"
></option>
</select>
</label>
</div>
|
As with the other form inputs on the page, the th:field
attribute determines the name
and id
attributes for the select
tag. We make an option
tag for each of the EventType
values, making use of the types
variable we passed in from the controller in
the previous step. We set the value
attribute for the
model data to be the EventType
value using th:value
. And the type name shown to the user
of the form as the displayName
of the type, using th:text
.
Once an event is created, to display its type
field in the table of all events, we’ll modify
templates/events/index.html
to include another column:
<!-- other table headers -->
<th>Type</th>
<!-- other event data -->
<td th:text="${event.type.displayName}"</td>
In this case, the type displayed is the value of the event object’s type
field, so the controller
method responsible for rendering this view does not need a types
variable passed in. To show the
more user-friendly view of the type value, we use the .displayName
field of EventType
.
Question
When we add a field to the EventType
enum from coding-events
, what is the strongest
reason why we don’t we write a setter method for that field?
Question
In coding-events
, say we change our template variable name in
EventController.displayCreateEventForm
so that EventType.values()
is now assigned to
a variable, categories
. Which of the template expressions in the following codeblock
from create.html
, if any, should be changed to reflect this update? Select all that apply.
27 28 29 30 31 32 33 34 35 36 | <div class="form-group">
<label> Type
<select th:field="${event.type}">
<option th:each="type : ${types}"
th:value="${type}"
th:text="${type.displayName}"
></option>
</select>
</label>
</div>
|
${event.type}
should be changed to ${event.category}
type : ${types}
should be changed to category : ${categories}
${type}
should be changed to ${category}
${type.displayName}
should be changed to ${category.displayName}