<p>I think there's a few ways to skin this cat, but <a href="https://craftcms.stackexchange.com/a/11656/1098">the most robust way</a> would probably be to listen to the the <code>selectElements</code> event for the <a href="https://github.com/pixelandtonic/Craft-Release/blob/master/app/resources/js/craft.js#L3660" rel="nofollow noreferrer"><code>BaseElementSelectInput</code></a> instances bound to each field's container element (the instance will be bound to the <code>&lt;div class="elementselect"&gt;</code> node, except for Categories fields where it'll be bound to the <code>&lt;div class="categoriesfield"&gt;</code> node, for some reason) and can be accessed by calling <code>$('.elementselect').data('elementSelect')</code>.</p>

<p>You can use the <code>.on()</code> method to listen to the actual events, here's one way to do it:</p>

<pre><code>$('.elementselect, .categoriesfield').each(function () {
    $(this).data('elementSelect').on('selectElements', onSelectElements);
});

function onSelectElements(e) {
    var $field = $(e.target);
    var selectedElements = e.elements;
}
</code></pre>

<p><strong>HUGE CAVEAT</strong></p>

<p>Depending on <em>when</em> your plugin's JavaScript runs, the <code>elementSelect</code> data attribute for the element select input DOM nodes may return <code>null</code>.</p>

<p>This is because Craft actually initialises the BaseElementSelectInput instances in some inline JavaScript injected into the source, and this JavaScript is, unfortunately, written to the page <em>after</em> your plugin's JavaScript resources are queued up (after any inline JavaScript your plugin adds, too).</p>

<p>In other words, if you need to hook into the BaseElementSelctInput instances on pageload, you'll need to <em>poll</em> for the <code>data('elementSelect)</code> attribute (ew, I know):</p>

<pre><code>$('.elementselect, '.categoriesfield').each(function () {
    var now = new Date().getTime();
    var getElementSelect = (function () {
        var elementSelect = $(this).data('elementSelect');
        if (elementSelect) {
            // Woo, I can haz elementSelect
            elementSelect.on('selectElements', onSelectElements);
        } else if (new Date().getTime() - now &lt; 5000) {
            // Poll for 5 secs (then give up)
            Garnish.requestAnimationFrame(getElementSelect);
        }
    }).bind(this)
    getElementSelect();
});
</code></pre>

<p>Hack alert: If you don't want to poll for the elementSelect instances, there is another way. Credit due, I learnt this trick from looking at <a href="https://github.com/benjamminf" rel="nofollow noreferrer">Benjamin Fleming's</a> source code:</p>

<pre><code>var elementSelectInit = Craft.BaseElementSelectInput.prototype.init;
Craft.BaseElementSelectInput.prototype.init = function () {
    elementSelectInit.apply(this, arguments);
    this.on('selectElements', onSelectElements);
    this.on('removeElements', onRemoveElements);
}

function onSelectElements (e) {
    console.log(e);
}
</code></pre>

<p>What the above does, is to basically hijack the BaseElementSelectInput class' <code>init</code> method, in order to add some custom event listeners <em>when each BaseElementSelectInput instance is initialised</em>. Works like a charm and – even if it's a huge hack – is quite a bit cleaner than the polling method, in my opinion.</p>

CC BY-SA 3.0
2016-09-19T10:13:11.290Z
Thanks Mats. That gets me up and running. I appreciate the additional considerations too!
Ben Parizek
CC BY-SA 3.0
2016-09-19T10:45:22.210Z
No worries Ben, happy it helped you out!
Mats Mikkel Rummelhoff
CC BY-SA 3.0
2016-09-19T09:16:00.383Z
2016-09-19T09:33:38.297Z
2017-04-13T12:51:00.303Z
Mats Mikkel Rummelhoff
<p>I have a situation where I'd like to watch for a change in an Element Select field and determine if any Elements have been selected or not.</p>

<p>Element Select fields have two <code>input</code> elements. One, is always present and never changes, and the other gets added and removed from the page depending on if any items have been selected. Here's a simplified version of the HTML:</p>

<pre><code>&lt;div class="field" id="fields-fieldhandle-field"&gt;

    {# This input field is always present and never changes #}
    &lt;input type="hidden" name="fields[assets]" value=""&gt;

    &lt;div class="elements"&gt;

        {# When you add or remove elements, this .element div and input 
           get added and removed from the DOM #}
        &lt;div class="element&gt;
            &lt;input type="hidden" name="fields[assets][]" value="430"&gt;
        &lt;/div&gt;    
    &lt;/div&gt;

&lt;/div&gt;
</code></pre>

<p>I've tried various listeners but so far they all get destroyed when the second input gets removed from the page, or never get added to the right input field if it is not on the page.</p>

<p>How do I listen for an element that may or may not exist on the page?</p>

<plugin-development><javascript>
How to watch for changes on an Element Select Relations field?
# How to watch for changes on an Element Select Relations field?

(Asked by: username_0 on 2016-09-19)

I have a situation where I'd like to watch for a change in an Element Select field and determine if any Elements have been selected or not.
Element Select fields have two input elements. One, is always present and never changes, and the other gets added and removed from the page depending on if any items have been selected. Here's a simplified version of the HTML:


    {# This input field is always present and never changes #}
    

    

        {# When you add or remove elements, this .element div and input 
           get added and removed from the DOM #}
        
            
    



I've tried various listeners but so far they all get destroyed when the second input gets removed from the page, or never get added to the right input field if it is not on the page.
How do I listen for an element that may or may not exist on the page?

**Tags:** plugin-development, javascript

---

## 1 answers

### Answer by username_1 on 2016-09-19. Score: 2 | Accepted answer

I think there's a few ways to skin this cat, but the most robust way would probably be to listen to the the selectElements event for the BaseElementSelectInput instances bound to each field's container element (the instance will be bound to the  node, except for Categories fields where it'll be bound to the  node, for some reason) and can be accessed by calling $('.elementselect').data('elementSelect').
You can use the .on() method to listen to the actual events, here's one way to do it:
$('.elementselect, .categoriesfield').each(function () {
    $(this).data('elementSelect').on('selectElements', onSelectElements);
});

function onSelectElements(e) {
    var $field = $(e.target);
    var selectedElements = e.elements;
}

HUGE CAVEAT
Depending on when your plugin's JavaScript runs, the elementSelect data attribute for the element select input DOM nodes may return null.
This is because Craft actually initialises the BaseElementSelectInput instances in some inline JavaScript injected into the source, and this JavaScript is, unfortunately, written to the page after your plugin's JavaScript resources are queued up (after any inline JavaScript your plugin adds, too).
In other words, if you need to hook into the BaseElementSelctInput instances on pageload, you'll need to poll for the data('elementSelect) attribute (ew, I know):
$('.elementselect, '.categoriesfield').each(function () {
    var now = new Date().getTime();
    var getElementSelect = (function () {
        var elementSelect = $(this).data('elementSelect');
        if (elementSelect) {
            // Woo, I can haz elementSelect
            elementSelect.on('selectElements', onSelectElements);
        } else if (new Date().getTime() - now < 5000) {
            // Poll for 5 secs (then give up)
            Garnish.requestAnimationFrame(getElementSelect);
        }
    }).bind(this)
    getElementSelect();
});

Hack alert: If you don't want to poll for the elementSelect instances, there is another way. Credit due, I learnt this trick from looking at Benjamin Fleming's source code:
var elementSelectInit = Craft.BaseElementSelectInput.prototype.init;
Craft.BaseElementSelectInput.prototype.init = function () {
    elementSelectInit.apply(this, arguments);
    this.on('selectElements', onSelectElements);
    this.on('removeElements', onRemoveElements);
}

function onSelectElements (e) {
    console.log(e);
}

What the above does, is to basically hijack the BaseElementSelectInput class' init method, in order to add some custom event listeners when each BaseElementSelectInput instance is initialised. Works like a charm and – even if it's a huge hack – is quite a bit cleaner than the polling method, in my opinion.

> **Comments:**
> **username_0**: Thanks Mats. That gets me up and running. I appreciate the additional considerations too!  
> **username_1**: No worries Ben, happy it helped you out!  

---

