1

Official docs for lightning:input did not show any keyboard event attributes yet. I have a dynamically created input form and I want to call a controller's method after hitting the enter key on a input text element.

I tried using jQuery to bind the input element with keyup method, but it doesn't seems to be working for me.

Component

 <aura:component>
    <ltng:require scripts="{!$Resource.jQueryLib + '/js/jquery-3.1.1.min.js'}" 
                  afterScriptsLoaded="{!c.afterScriptsLoaded}"/>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <p>Dynamically created input Text</p>
    {!v.body}
</aura:component>

Controller.js

 doInit : function(cmp, event, helper)
    {
        $A.createComponent(
            "lightning:input",
            {
                "label": "First Name",
                "type": "text",
                "name":"testing",
                "class":"inputTestClass"
            },
            function(newText, status, errorMessage){
                if (status === "SUCCESS") {
                    var body = cmp.get("v.body");
                    body.push(newText);
                    cmp.set("v.body", body);
                    console.log("I printed out after scripts loaded");
                }
                else if (status === "INCOMPLETE") {
                    console.log("No response from server or client is offline.")
                    // Show offline error
                }
                else if (status === "ERROR") {
                    console.log("Error: " + errorMessage);
                    // Show error message
                }
            }
        );                      
    },
  afterScriptsLoaded:function(component, event, helper)
  {
    console.log(jQuery(".inputTestClass").children().children("input"));  
    //returns nothing; 
    //expected an input element
    jQuery(".inputTestClass").children().children("input").keyup(function()
    {
            console.log("did I get it?") // Not printed on the console
        });    
   }

Its because, the afterScriptsLoaded is executed first before the init handler called.

1

I think if you can store the input component using an onfocus event, you can then capture a keyboard event by either:

either attaching a listener to the window or wrapping everything in a span or div with a onkeyup event.

Markup:

<span onkeyup="{!c.handleKeyup}">
  <lightning:input label="Name" name="myname" onfocus="{!c.handleFocus}"/>
</span>

Controller:

handleFocus: function(component, event, helper) {
    var src = event.getSource();
    component.set("v.currentInput",src);
},

handleKeyup: function(component, event, helper) {

    //you have the relevant input + the keyboard event
    var currentInput = component.get("v.currentInput");

    if(event.key == 'Enter') {
      console.log(event);
        //do something
    }
}

EDIT

Forgot to say, to add your focus handler to the dynamically created component, use component.getReference() to get a ref to the method. Eg in your component creation call, do something like this:

"lightning:input",
 {
   "aura:id": "findableAuraId",
   "onfocus": component.getReference("c.handleFocus"),
   "label": "your label",
   "name": "your name"
 },

In the handleKeyup method, you can then do whatever processing you need as you have both the keyboard event and the relevant component.

  • Thanks for your answer. I haven't tried your method yet as I have found another work around using custom rendering in renderer.js. I'll post my answer as well. – sam_s Jun 30 '17 at 16:40
1

After a fair amount of googling and with the help of other SFSE answers, using the concept of Custom Renderer I am able to achieve what I was hoping for.

Step 1 : I added an extra attribute to the component to check whether my jQuery has been loaded

   <aura:attribute name="scriptsLoaded" type="boolean" default="false" />

Step 2: I set the variable to true in the controller method

afterScriptsLoaded:function(component, event, helper)
{
     component.set("v.scriptsLoaded", true);
     // This will trigger the re-render code in the renderer.js  
}

Step3: In renderer.js

rerender: function(component, helper) 
{
        this.superRerender();
        var areScriptsLoaded = component.get("v.scriptsLoaded");
        if(areScriptsLoaded){
            helper.postRender(component);    
        } 
}

Step4: In helper.js

postRender:function(component){ 
jQuery(".inputTestClass").children().children("input").keyup($A.getCallback(function(event){
                if(event.keyCode === 13)
                {
                     console.log('Enter key clicked');
                }

          }));

 }

Always use $A.getCallback() for any components if you are modifying outside framework.

  • I'm surprised that works given that you are modifying a component. Normally that's not allowed with Locker Service on. What API version is this component? – Caspar Harmer Jun 30 '17 at 17:20
  • And yes, I should have told you - you can't perform operations on elements in the init (or shortly after the init) as the elements are not guaranteed to be there yet. You could simplify your code here by leaving out the tag and overriding the afterRender method rather than the reRender method. – Caspar Harmer Jun 30 '17 at 17:22
  • @CasparHarmer I'm a bit surprised too. I've activated the locker service in our org and it is on v39. – sam_s Jun 30 '17 at 18:44
  • @CasparHarmer I've tried afterRender method initially by reading the doc but for some reason, afterRender method fires before the afterScriptsLoaded method. May be that's because the component in the question is actually a child of another parent component. I'm still trying to wrap my head around this whole flow of 'renderer.js'. – sam_s Jun 30 '17 at 18:52
  • Ah yes, I hadn't taken into account loading jquery. Do you actually need jQuery? I like this site: youmightnotneedjquery.com – Caspar Harmer Jun 30 '17 at 20:59

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.