Ratings Icons

This example shows how to associate icons with picklist values and combine the appropriate icon with the picklist label.

While this example uses emojis, it’s possible to use icons in other formats, like SVG or font-based icons.

../../../../../_images/ratings-icons.gif

Example Code

Download the sample page for this field renderer here, or see the example code below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
// Let's configure our icons at the top of the field renderer.
// This let's us avoid hardcoding values further down in our code,
// and makes them easier to change if we wish to later on.
const hotIcon = "🔥",
    warmIcon = "➕",
    coldIcon = "🥶",
    defaultIcon = "🎱";
// Since we'll also be needing to retrieve the appropriate icon
// in both read and edit modes, let's define a reusable function
// to handle that at the top as well.
const determineIcon = (value) => {
    switch (value) {
        case 'Hot':
            return hotIcon;
        case 'Warm':
            return warmIcon;
        case 'Cold':
            return coldIcon;
        default:
            return defaultIcon;
    }
}

const FieldRenderer = skuid.component.FieldRenderer;
return new FieldRenderer({
    readModeStrategy: "virtual",
    read: function (fieldComponent) {
        let h = fieldComponent.h,
            context = fieldComponent.cpi.getContext(),
            { field, model, row, value } = context;

        // Since we're dealing with picklists, make sure
        // to retrieve the *label* for our UI element.
        // First let's filter the picklistEntries
        // on the field for our value.
        let entry = field.picklistEntries.filter(entry => {
            return entry.value === value
        })
        // With the right entry selected, set up a reference to
        // the label key. If there is no value and thus no
        // appropriate entry, then use the default rating.
        let label = entry[0] ? entry[0].label : "No rating"

        // Note that the filtering above returns an array also.
        // This array *should* only have one element though.
        // We'll reference it with label[0]

        // The VNode returned for read mode doesn't need any
        // HTMl attributes, so just pass in the icon
        // Use the determineIcon() function, passing in
        // the value of the row, to get the proper icon.
        // Also, let's place the label in a template literal
        // so there can be a space between the icon and label text.
        return h("div",
            [`${determineIcon(value)}  ${label}`]
        )
    },

    editModeStrategy: "virtual",
    edit: function (fieldComponent) {
        let h = fieldComponent.h,
            context = fieldComponent.cpi.getContext(),
            { field, model, row, value } = context;

        return h("select",
            // We need to set up the proper event handling
            // to update the model with the value selected here,
            // so let's do that in the attribute object.
            {
                oninput(event) {
                  model.updateRow(row,
                      { [field.id]: event.target.value },
                      { initiatorId: fieldComponent.id }
                  );
                },
                onblur(event) {
                    fieldComponent.cpi.onInputBlur();
                },
                // Using maquette's afterCreate() function,
                // make sure the edit mode dropdown reflects
                // the value of the row. Otherwise, the dropdown
                // displays the first picklist entry, which
                // can confuse users.
                afterCreate(element) {
                    element.value = value;
                },
            },
            // Next, generate "option" elements for each picklist entry.
            // Let's use the field metadata's picklist entries to set up
            // the proper structure. We'll also reuse determineIcon()
            // so we can show an icon beside the value string.
            field.picklistEntries.map(entry => {
                return h("option",
                    { value: entry.value },
                    [`${determineIcon(entry.value)}  ${entry.label}`]
                )
            }),

        );
    }
});