0
\$\begingroup\$

In my web application, a user will click a button which will call a function that triggers an AJAX call. That function accepts a single argument. I would like to be able to put that function in place of the anonymous function in the jQuery event handler. I suspect that this is a scoping issue...

Here is my working code:

(function () {
 'use strict';

  var postId;

  function userAddFlagToPost (userId) {
    return $.ajax({
      type: 'POST',
      timeout: 1000 * 3;,
      url: '/someApi/postId',
      data: {
        userId: userId
      },
    }).done(onFlagSubmitDone)
      .fail(onFlagSubmitDone);
  }

  function onLoggedIn() {
    var userId = getCookie('some_user_auth') || null;

    $(SELECTORS.POST_FLAG).on('click', function() {
      postId = $(this).data('postId');
    });

    $(SELECTORS.SUBMIT_BUTTON).on('click', function() {
      userAddFlagToPost(userId);
    });
  }

  function init() {
    eventQ.register(onLoggedIn);
  }

  init();
})();

I would like to be able to do:

$(SELECTORS.SUBMIT_BUTTON).on('click', userAddFlagToPost(userId));

I'd appreciate any info or advice on how to go about refactoring this code, thanks!

\$\endgroup\$
5
  • \$\begingroup\$ I fear that this is off-topic, it sounds like you are asking how to implement functionality. Please only post code that already accomplishes the task at hand. \$\endgroup\$
    – Malachi
    Sep 23, 2018 at 20:04
  • \$\begingroup\$ My code is functional and does what I want. I am just looking for help to refactor the callbacks. \$\endgroup\$ Sep 24, 2018 at 17:08
  • \$\begingroup\$ @malachi can you please remove this question from being on hold? \$\endgroup\$ Sep 24, 2018 at 22:46
  • \$\begingroup\$ The problem is the following line: "I would like to be able to put that function in place of the anonymous function in the jQuery event handler." 1) I'm not sure what you mean with that, but that's my lack of JS knowledge showing and 2) that's a feature request, not a request for review. If the code is lacking a feature you want to have anyway, it's not working yet the way you want it to work. That's why it got closed, I presume. \$\endgroup\$
    – Mast
    Sep 27, 2018 at 15:55
  • \$\begingroup\$ 1. I'm asking for advice on how to refactor my existing, working code. 2. How is it a feature request when the code already does what I want. I even specified I would appreciate "any info or advice"...Should I have just posted the code and not said anything? Or maybe this should have been a question for Stack Overflow? Last thing I want to do is abuse/misuse this site. Thx. \$\endgroup\$ Sep 27, 2018 at 23:24

1 Answer 1

1
\$\begingroup\$

It seems that what you want is a partially-applied function. One way this can be achieved is using Function.prototype.bind().:

$(SELECTORS.SUBMIT_BUTTON).on('click', userAddFlagToPost.bind(null, userId));

Pass null as the first argument unless the context needs to be set (e.g. to this for the same context?) and then userId as the second argument will pass that as the first argument to the function. Then note that userAddFlagToPost() would then receive the event Event eventobject argument per the `.on() method.

With this approach, the function is not invoked (as it would be with your proposed syntax) but instead the partially applied function is invoked when the click handler is applied.

See this demonstrated in the snippet below:

(function() {
  'use strict';

  var postId;
  var SELECTORS = {
    SUBMIT_BUTTON: '#submitButton',
    DISPLAY_ELEMENT: '#displayElement'
  };

  function userAddFlagToPost(userId) {
    var text = 'userId passed to userAddFlagToPost: ' + userId + ' count of arguments: ' + arguments.length;
    Array.from(arguments).forEach(function(argument, index) {
      text += '<br> typeof arg[' + index + ']: ' + (typeof argument);
    });
    $(SELECTORS.DISPLAY_ELEMENT).html(text);
  }

  function init() {
    var userId = 1337; //hard code for now
    $(SELECTORS.SUBMIT_BUTTON).on('click', userAddFlagToPost.bind(null, userId));
  }
  init();
})();
#displayElement {
  border: 1px solid #0f0;
  margin: 4px;
  padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<button id="submitButton">Click this to see the partially function called</button>
<div id="displayElement"></div>

Note that there is a jQuery shortcut method .click() that could be used in place of .on('click'):

$(SELECTORS.SUBMIT_BUTTON).click(userAddFlagToPost.bind(null, userId));
\$\endgroup\$
2

Not the answer you're looking for? Browse other questions tagged or ask your own question.