Search code examples
javascriptbindevent-listener

How do you pass parameters to eventListener functions?


I'm practicing separating my code into modules for more readability.

I'm trying to figure out why my event handler function isn't receiving the parameter I bind to it.

import domElements from "./domElements.js";
import Gifs from "./gifModel.js";
import * as view from "./viewController.js";

//state 
let state = {
    imagesLoaded: 0,         //number of images rendered to DOM so far
    page : 0,                //keep track of offset of data from api
    gifs : new Gifs(),       //request data from API
    dom : new domElements(), //definition of dom elements
    view : view
} 

//initialize app
async function init () {

    //fetch initial data
    await state.gifs.fetchQuery('candy', state.page * 50);
    
    /***Here is where I try to bind the code***/
    window.addEventListener('scroll', state.view.findEndOfPage.bind(state)); 
 
    //...
}

//run code
init(); 

/*****How findEndOfPage is defined in a separate file: ****/
export async function findEndOfPage(){
    
    const bottomOfPage = document.body.offsetHeight;
    if(window.innerHeight + window.pageYOffset >= bottomOfPage){
        //if current images can still be retrieved from state
        if(state.imagesLoaded < state.gifs.imgUrl.length){
        
            generateImages();
        
        //otherwise, load more images
        } else{
            state.page++;
            await state.gifs.fetchQuery('cartoon', state.page * 50);
            generateImages();
        }
    }
}

//Error Message
viewController.js:27 Uncaught (in promise) ReferenceError: state is not defined
    at _callee$ (viewController.js:27)
    at tryCatch (runtime.js:63)
    at Generator.invoke [as _invoke] (runtime.js:293)
    at Generator.next (runtime.js:118)
    at asyncGeneratorStep (gifModel.js:26)
    at _next (gifModel.js:26)
    at gifModel.js:26
    at new Promise (<anonymous>)
    at Event.<anonymous> (gifModel.js:26)
    at Event.findEndOfPage (viewController.js:27)

Solution

  • The bind method "binds" the first argument to the "this" keyword, in your code you can use "this" to access "state" inside findEndOfPage.

    All other arguments (second, third...) are passed to the function, but you still need to add them to the function parameters.

    to use the "state" variable inside the function you must pass null as the first argument and state as the second, and add "state" as a parameter to findEndOfPage.

    window.addEventListener('scroll', state.view.findEndOfPage.bind(null, state));
    
    export async function findEndOfPage(state) {
        //...
    }
    

    Update

    All other arguments used when calling the function will be passed after the ones used in bind, in your case event will be passed after state.

    to keep event as the first argument you can use a closure

    window.addEventListener('scroll', state.view.findEndOfPage(state));
    
    export function findEndOfPage(state) {
        return async function(event) {
            // your code goes here
        }
    }