4

There is this post that talks about how to fire a function once the user is done typing. How can this be implemented in an aura component? This is what I have so far, but it doesn't work.

<aura:component controller="SearchController" implements="forceCommunity:availableForAllPageTypes">
    <aura:attribute name="searchValue" type="String"/>
    <aura:attribute name="articles" type="List" default="[]"/>
    <aura:attribute name="timer" type="Object"/>

                <span onkeyup="{!c.onKeyUpHandler}" onkeydown="{!c.onKeyDownHandler}">
                    <lightning:input aura:id="searchValue" 
                                     type="search" 
                                     placeholder="Enter text..." 
                                     class="fl sidenav-search"/>
                </span>

</aura:component>

component.js

onKeyUpHandler:function(component, event, helper) {
    let timer = component.get("v.timer");
    timer = setTimeout(helper.handleSearch(component,event,helper), 1000) 

    component.set("v.timer", timer);
},
onKeyDownHandler:function(component) {
    let timer = component.get("v.timer");
    clearTimeout(timer);

    component.set("v.timer", timer);
}
  • My helper function that calls apex gets called each keystroke. No errors. Functionality still works. I’m not sure how to debug it cause I don’t fully understand the solution from the link I shared. – Tyler Zika Sep 6 '19 at 3:32
5

In JavaScript, when you want to set a callback, you need to bind to a function. Assuming you also want to be in the Aura life cycle (which is almost always yes), the resulting Aura version of the code looks like this:

onKeyUpHandler:function(component, event, helper) {
    let timer = setTimeout(
      $A.getCallback(
        helper.handleSearch.bind(helper,component,event,helper)
    ), 1000) 
    component.set("v.timer", timer);
},
onKeyDownHandler:function(component) {
    let timer = component.get("v.timer");
    clearTimeout(timer);
    component.set("v.timer", null);
}

Notable changes:

  • v.timer is set to null after clearing the timer.
  • v.timer is not read before setting it via setTimeout.
  • $A.getCallback ensures you're in an Aura life cycle event.
  • .bind(helper, component, event, helper) returns a bound function reference with this set to helper (the same behavior as if you'd called it directly). Without this, the original code was calling the method immediately instead of waiting 1,000 ms.
  • That's for your efforts. I implemented what you suggested, and I do get a delay, but the function still fires multiple times after a few seconds: imgur.com/a/erTHXYI – Tyler Zika Sep 7 '19 at 0:48
  • The behavior I want: say the user types their name, there is a 2 second buffer after they finish typing their name. If they start typing their last name 1 second after finishing their first name, the search function does not fire. Once they've stopped typing for 2 seconds, then the function fires. – Tyler Zika Sep 7 '19 at 0:52
  • I found a solution here: salesforce.stackexchange.com/questions/71557/… – Tyler Zika Sep 7 '19 at 1:30
  • I probably implemented yours wrong. The solution I found is a little different from yours, but I'm not one to judge cause I'm not a JavaScript expert. – Tyler Zika Sep 7 '19 at 1:30
  • 1
    @javanoob Whoops, yeah, nice catch. – sfdcfox Sep 7 '19 at 20:17
0

This worked for me. I don't even need the onKeyDownHandler anymore.

onKeyUpHandler:function(component, event, helper) {
    var timer = component.get('v.timer');
    clearTimeout(timer);

    var timer = setTimeout(function(){
        var newlst = [];
        helper.handleSearch(component,event,helper);
        clearTimeout(timer);
        component.set('v.timer', null);
    }, 700);

    component.set('v.timer', timer);
},

and the helper is important. The utility.getDataParams is just a function from a static resource that I've generalized to enqueue server side apex for data retrieval.

handleSearch : function(component, event, helper) {
    let searchValue = component.find("searchValue").get("v.value");

    if(searchValue.length > 1) {
        this.searchForArticles(component, searchValue);
    } else {
        component.set("v.articles", []);                      
    }
},   
searchForArticles : function(component, searchValue) {
    let params = {searchValue:searchValue}
    //var d = new Date();
    //console.log(params);
    //console.log(d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds());

    $A.getCallback(function() {
        utility.getDataParams(component, "c.getArticles", params, $A.getCallback(function(error, value) {
            console.log(value);
            component.set("v.articles", 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.