Search code examples
javascriptthisfetch-apiform-data

FormData Object Throwing An Error When Changed To An Arrow Function - JavaScript


I have some JavaScript fetch() code that sends data to a MySQL database and prevents a hard page refresh. The backend code is written in PHP. This all works OK, but I decided to change the functions to ES6 arrow functions and an issue has arison around the FormData() object.

In the code below all of the functions have been changed to arrow functions apart from the function on line 3.

When I change the one on line 3 to an arrow function i.e. i.addEventListener('submit', (e) => { ... I get the following error message:

Uncaught TypeError: Failed to construct 'FormData': parameter 1 is not of type 'HTMLFormElement'

...which seems to relate to the this context?

When I remove this as a parameter, it throws an error in my PHP and I get Undefined index: create-board-name in relation to $_POST['create-board-name'], with 'create-board-name' being the name of the button that submits to the database.

My question is thus, how do I use an arrow function with FormData() and fetch(), if the arrow function affects the context of how this is interpreted?

JavaScript

if (form) {
    form.forEach(i => {
    i.addEventListener('submit', function(e) {
        if (e.submitter && e.submitter.classList.contains('js-fetch-button')) {
                e.preventDefault();

                var formData = new FormData(this);

                formData.set(e.submitter.name, e.submitter.value);
                formData.set('json_response', 'yes'); // relates to json encoding in the PHP shown further down

                fetch(
                    theURL, {
                    method: 'post',
                    body: formData
                })
                .then((response) => {
                    if (response.status === 200) {
                        response.json().then((json) => {

                            // --- stuff happens here

                        });
                    }
                }).catch((error) => {
                    console.error(error);
                })
            }
        })
    }) 
}

PHP (which I don't think is the issue)

Although I don't think the PHP is the problem I've included it below. Basically when a new board is created it updates the database and then returns this information to the page as JSON so that the new board information can be used immediately after creation if necessary.

    // insert into database
    $stmt = $connection->prepare(
        "INSERT INTO boards (board_name, user_id) 
        VALUES (:board_name, :user_id )"
    );
    $stmt->execute([
        ':board_name' => $create_board_name,
        ':user_id' => $sessionId
    ]);

    // fetch as JSON
    if(isset($_POST['json_response'])) {
        $board_stmt = $connection->prepare(
            "SELECT * FROM boards 
            WHERE user_id = :user_id AND board_name = :board_name 
            ORDER BY board_id DESC"
        );

        $board_stmt -> execute([
            ':user_id' => $sessionId,
            ':board_name' => $create_board_name
        ]); 

        $board_row = $board_stmt->fetch();

        header('Content-type: application/json');
        echo json_encode($board_row);
        exit;
    }

Solution

  • When you change it to arrow function, this will be referencing a definition context of the arrow function (class, another function, where you defined that code) instead of the clicked Form element.

    How to access form data in arrow function:

    1. From what I see you already have a reference to the Form element in i variable, what you can do then:
    var formData = new FormData(i);
    
    1. Another option is to use target option of the event in the event handler.
    var formData = new FormData(e.target);