AEM: Setting maximum items for a multifield

2018-07-13

There is an Adobe published article that shows how to set a max on the amount of items allowd in a multifield, you can find it here. The content of the article is fine if you are using the older CoralUI 2-based dialog components, in this tutorial I'll show you how its done for the CoralUI 3-based dialog components.

NOTE: You can find the migration guide here

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
...

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
		  xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
		  xmlns:granite="http://www.adobe.com/jcr/granite/1.0"
...

<colors
		jcr:primaryType="nt:unstructured"
		sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
		fieldDescription="Click 'Add field' to add a new color"
		fieldLabel="Colors"
		composite="{Boolean}true">
	<granite:data
			jcr:primaryType="nt:unstructured"
			max-items="2"/>
	<field
			jcr:primaryType="nt:unstructured"
			sling:resourceType="granite/ui/components/coral/foundation/container"
			name="./colors">
		<items jcr:primaryType="nt:unstructured">

			<color
					jcr:primaryType="nt:unstructured"
					sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
					fieldDescription="Fill in a hex value: # and 6 characters"
					fieldLabel="Color"
					name="color"/>

		</items>
	</field>
</colors>

...

We specify a max-items attribute in the granite:data part of the xml so that we can later on use it in our clientlib. You can see here that the multifield now has that data- attribute:

The clientlib

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
(function ($, $document) {

	"use strict";

	// **************************************************************************
	// ** CONSTANTS
	// **************************************************************************

	const EVENT_CLICK = "click";

	const ATTRIBUTE_MULTIFIELD_ADD = "coral-multifield-add";
	const ATTRIBUTE_MULTIFIELD_MAX_ITEMS = "data-max-items";

	const SELECTOR_MULTIFIELD_ADD_ITEM_BUTTON = `button[${ATTRIBUTE_MULTIFIELD_ADD}]`;
	const SELECTOR_MULTIFIELD_ITEM = "coral-multifield-item";

	// **************************************************************************
	// ** CLASSES
	// **************************************************************************

	class Listener {

		constructor(selector, event, handler) {
			this.selector = selector;
			this.event = event;
			this.handler = handler;
		}

		getSelector() {
			return this.selector;
		}

		getEvent() {
			return this.event;
		}

		getHandler() {
			return this.handler;
		}
	}

	// **************************************************************************
	// ** LISTENER HANDLERS
	// **************************************************************************

	function multifieldMaxItemsHandler(context) {

		const $field = $(context).parent();
		const maxSize = $field.attr(ATTRIBUTE_MULTIFIELD_MAX_ITEMS);

		if (maxSize) {

			const ui = $(window).adaptTo("foundation-ui");
			const currentSize = $field.children(SELECTOR_MULTIFIELD_ITEM).length;

			if (currentSize >= maxSize) {
				ui.alert("Warning", "Maximum  " + maxSize + " items are allowed!", "notice");
				return false;
			}
		}
	}

	// **************************************************************************
	// ** LISTENERS
	// **************************************************************************

	const listeners = [];
	listeners.push(new Listener(SELECTOR_MULTIFIELD_ADD_ITEM_BUTTON, EVENT_CLICK, multifieldMaxItemsHandler));

	// **************************************************************************
	// ** REGISTER LOGIC
	// **************************************************************************

	$document.on("dialog-ready", function () {

		$.each(listeners, function (index, listener) {
			$(listener.getSelector()).on(listener.getEvent(), function () {
				return listener.getHandler()(this);
			})
		});
	});

})($, $(document));

The JavaScript is really straightforward:

  1. Add a click listener to the add button.
  2. Read the data-max-items attribute from the multifield.
  3. Check the current items in the multifield, if this is larger than the maximum amount of items allowed -> show an error message.
Created by Jeroen Druwé