0

EDIT 1

This question was closed almost immediately, since it's supposed to be a duplicate. I beg to differ since the "original" question is about general argument binding, where this question (correctly) resolves a new issue via @Phil's comment. I believe that .bind prepending arguments before the hidden argument event on which you may then call event.preventDefault() is not common knowledge for all. For other's sake, I believe this question will stay open.

EDIT 2

Another knowledge bomb (no sarcasm) from @Phil. In original question it is shown, that instead of .addEventListener('event', callable.bind(this, data)) a possibly clearer way would be .addEventListener('event', e => callable(e, data)) meaning using an intermediate anonymous function that you may put arguments into. A bonus here is that any data fetched (e.g. from a form) is fetched at the time of triggering event, which is clearly advantageous.

ORIGINAL QUESTION

I likely didn't do the title rightly, so please comment a more appropriate one for me to edit.

Best explaining with an example.

This works:

<script>
form.addEventListener('submit', (e) => {
    e.preventDefault();
    const data = {
        name: form.name.value,
    };
    fetch('logics-url.php', {
            ...,
            body: JSON.stringify(data),
        })
        .then(r => r.json())
        .then(d => console.log(d))
        .catch(e => console.error(e));
});
</script>

Then I need the same logic-url.php called with different (additional) data when a button outside of the form is clicked.

First I extracted the callable from inside of the addEventListener and this still works:

<script>
const callable = (e) => {
    e.preventDefault();
    const data = {
        name: form.name.value,
    };
    fetch('logics-url.php', {
            ...,
            body: JSON.stringify(data),
        })
        .then(r => r.json())
        .then(d => console.log(d))
        .catch(e => console.error(e));
}
form.addEventListener('submit', callable);
button.addEventListener('click', callable); // button *is* defined in this scope
</script>

Now I want to send different data these two addEventListeners and this where it fails me.

<script>
const callable = (e, data) => {
    e.preventDefault();
    // Removed data here
    fetch('logics-url.php', {
            ...,
            body: JSON.stringify(data),
        })
        .then(r => r.json())
        .then(d => console.log(d))
        .catch(e => console.error(e));
}

const data1 = {
    name: form.name.value,
};
form.addEventListener('submit', callable.bind(null, data1));

const data2 = {
    name: form.name.value,
    trigger: 1,
};
button.addEventListener('click', callable.bind(this, data2));
</script>

I foolishly tried binding e, when it does not exist yet, so I removed it. Then (as you can see) I tried binding null and this and they both resulted in error:

# console
Uncaught ReferenceError: e is not defined at callable

I tried different variations but most resulted in the above error.

I also tried passing just dataN as a lone parameter and it resulted in:

# console
POST {...}/logics-url.php 400 (Bad Request)
Error: SyntaxError: Unexpected token < in JSON at position 0

Do I have to duplicate my code or is there another way?

s3c
  • 1,481
  • 19
  • 28
  • 1
    `bind` just binds the `this` context. An Event's `this` context is called in the context of to the Element which it belongs to. You want to do like `someElement.addEventListener('click', ()=>{ yourFunc.call(someContext, arg); } });` – StackSlave Feb 11 '21 at 00:48
  • 1
    Your issue is that `Function.prototype.bind()` **prepends** arguments. Prepending `data` means that `callable` should be defined with args `(data, e)` – Phil Feb 11 '21 at 00:49
  • 1
    @StackSlave `Function.prototype.bind()` can also prepend function arguments. For example `((...args) => console.log(...args)).bind(null, 1, 2)(3)` will log "1 2 3" – Phil Feb 11 '21 at 00:54
  • 1
    Note that the `EventObject` is the only argument passed to an EventListener, though. – StackSlave Feb 11 '21 at 01:03
  • [[1]] I don't know why this question was closed, because the "original" one is asking just about normal argument binding, and *not* about the `e.preventDefault()` intricacy. [[2]] @Phil you're the man! I had no idea that the arguments are prepended. Although I now realized that I need to update `let data1` and `let data2` on input, since it (logically) get form inputs on page load, hence they are empty strings. Thank you. – s3c Feb 11 '21 at 01:29
  • I've added another duplicate that I believe answers your questions regarding `Function.prototype.bind()`. Also, I don't know what you mean by _"hidden argument `event`"_. The arguments passed to the event handler are explained [in the documentation](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#the_event_listener_callback)... _"the callback accepts a single parameter: an object based on `Event` describing the event that has occurred"_ – Phil Feb 11 '21 at 01:44
  • 1
    FYI, there's nothing wrong with having a question closed as a duplicate. It helps others find answers to their similar problems by increasing the possible search results – Phil Feb 11 '21 at 01:49
  • After your explanation I cannot argue with that. If you feel (he he) that the Q should be deleted, I will do so. Otherwise I provided explanations in the beginning of OP. EDIT: A bit late... never mind. – s3c Feb 11 '21 at 01:50

0 Answers0