5

How do you add a change listener on an input date component that has been changed via the date picker?

Here's my current approach that does not work:

.app file

<aura:application >
    <ui:inputDate aura:id="dateField" label="Birthday" value="2014-01-30" displayDatePicker="true" change="{!c.handleDateChange}"/>
</aura:application>

Controller

({
    handleDateChange : function(component, event, helper) {
        console.log('date change');
    }
})

For contrast, a listener can be set on an input text field with the same approach (the below code works)

.app file

<aura:application >
    <ui:inputText label="Name" change="{!c.handleTextChange}"/>
</aura:application>

Controller

({
    handleTextChange : function(component, event, helper) {
        console.log('text change');
    }
})

Some things that I've noticed while testing:

  • Hitting 'enter' when the cursor is in date input field will cause the page to refresh
  • Hitting 'tab' when the cursor is in the date input field will cause the 'change' event to fire and the controller logs the 'date change' message to the console
4

You should be able to add the handlers after creation - The reason being is because you don't need to make your aura:id values unique.

If there are multiple components with the same local ID, find() returns an array of the components.

source

So with that in mind, in your iteration, give the input dates all the same id of say... aura:id="repeatedDate" and reference them in a loop on init:

var dateInputs = component.find("repeatedDate");

for (var i = 0; i < dateInputs.length; i++) {
  var dateInput = dateInputs[i];
  if (dateInput) {
    dateInput.addHandler("valueChange", component, "c.handleDateChange");
  }
}

Note - I'm not sure of the exact name for the valueChange event - you'll need to check the docs for this, or even consult the aura github project.


Note, there is another technique that SHOULD work, but doesn't - I'll put it in for reference, as it probably will at some point:

var cmpArr = component.find({ instancesOf : "ui:dateInput" });
for (var i = 0; i < cmpArr.length; i++) {
    var outputCmpArr = cmpArr[i];
    outputCmpArr.addHandler("valueChange", component, "c.handleDateChange");
}

(There are a couple of problems with this technique, one of which is supposed to be fixed by performing a find on the parent of the iterator list first and running a find off that - but I wasn't able to get that to work either)

1

This is not the behavior I would expect, however, I was able to reproduce this in my own environment so at least you know it isn't you. I'm not sure if this will fit your use case, but I was able to get the change event to fire with the date picker using this method.

<aura:application >
    <aura:handler name="init" value="{!this}" action="{!c.myAction}"/>
    <aura:handler name="change" value="{!v.date}" action="{!c.handleDateChange}"/> 

    <ui:inputDate aura:id="dateField" value='{!v.date}' label="Birthday" displayDatePicker="true"/>
</aura:application>

I'm setting the value of v.date on initialization.

Here is the controller code:

({
    myAction : function(component, event, helper) {
        component.set('v.date', '2014-01-30');
    },
    handleDateChange : function(component, event, helper) {
        console.log('date change');
    },
    handleTextChange : function(component, event, helper) {
        console.log('text change');
    }
})

Hope this helps!

2
  • 1
    Thanks! Unfortunately I want to use the input in an iteration component and it seems that aura:handler components cannot be created within the iteration component.
    – bafuda
    Aug 18 '16 at 21:07
  • 1
    You can add them after - check out my answer. Aug 18 '16 at 21:30
1

This bug only occurs when lockerservice is turned on

A workaround that doesn't have any of the downsides of the above solutions (one requires adding listener in JS and the other won't work within an iteration component) is to wrap the input date component in a wrapper that has a change listener on the date value and fires an event when the value changes.

InputDateWrapper.cmp

<aura:component >
    <aura:handler name="init" value="{!this}" action="{!c.init}"/>

    <aura:registerEvent name="dateChange" type="c:ChangeEvent"/>

    <aura:attribute name="object" type="Object" description="The object"/>
    <aura:attribute name="field" type="String" description="The date field"/>
    <aura:attribute name="value" type="Date"/>
        <!-- Unlike the 'change' event attribute on ui:inputDate, this change handler fires -->
        <aura:handler name="change" value="{!v.value}" action="{!c.handleChange}"/>
    <aura:attribute name="class" type="String"/>
    <aura:attribute name="disabled" type="Boolean"/>
    <aura:attribute name="displayDatePicker" type="Boolean"/>
    <aura:attribute name="errors" type="List"/>
    <aura:attribute name="format" type="String"/>
    <aura:attribute name="label" type="String"/>
    <aura:attribute name="labelClass" type="String"/>
    <aura:attribute name="langLocale" type="String"/>
    <aura:attribute name="required" type="Boolean"/>
    <aura:attribute name="requiredIndicatorClass" type="String"/>
    <aura:attribute name="updateOn" type="String"/>

    <ui:inputDate value="{!v.value}" 
        class="{!v.class}" 
        disabled="{!v.disabled}" 
        displayDatePicker="{!v.displayDatePicker}" 
        errors="{!v.errors}" 
        format="{!v.format}"
        label="{!v.label}" 
        labelClass="{!v.labelClass}" 
        langLocale="{!v.langLocale}" 
        required="{!v.required}" 
        requiredIndicatorClass="{!v.requiredIndicatorClass}" 
        updateOn="{!v.updateOn}"/> 
</aura:component>

InputDateWrapperController.js

({
    init : function(cmp) {
        var obj = cmp.get('v.object');
        var field = cmp.get('v.field');
        var value = obj[field];
        cmp.set('v.value', value);
    },

    handleChange : function(cmp) {
        var obj = cmp.get('v.object');
        var field = cmp.get('v.field');
        var value = cmp.get('v.value');

        if (obj[field] != value) {
            obj[field] = value;
            var changeEvent = cmp.getEvent('dateChange');
            changeEvent.setParam('value', obj);
            changeEvent.fire();
        }
    }
})

ChangeEvent.evt

<aura:event type="COMPONENT" description="Event fired on change">
    <aura:attribute type="Object" name="value" description="Value changed"/>
</aura:event>
1

Instead of doing all the hard work like using events and all.

You can use blur event instead of change event.

0

Use Select instead of change as it will fire action on selecting value.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.