user1640189
user1640189

Reputation: 113

How to work with callbacks in meteor?

I've created a helper for displaying a generic modal in my Meteor app (in coffeescript).

Here's modal.coffee:

showModal = (modalType, title, body, callback) ->
  validModals = [ "Error", "YesNo" ]

  if not modalType in validModals
    alert "Invalid modal type specified"    # @todo - find a better way of handling this error

  Session.set "modalType", modalType
  Session.set "modalTitle", title or ""
  Session.set "modalBody", body or ""
  modalCallback = callback or undefined
  Session.set "showModal", true

Template.modal.title = () ->
  Session.get "modalTitle"

Template.modal.body = () ->
  Session.get "modalBody"

Template.modal.response = () ->
  switch Session.get "modalType" 
    when "Error"
      [{
        css: 'cancel',
        message: 'OK'
      }]
    when "YesNo"
      [
        {
          css: 'cancel',
          message: "No"
        },
        {
          css: 'btn-primary',
          message: "Yes"
        },
      ]

Template.page.shouldShowModal = () ->
  Session.get "showModal"

Template.modal.events {
  'click .cancel': ->  
    Session.set "showModal", false
    cb = modalCallback
    alert "here " + cb
    if cb
      cb(false)
  'click .btn-primary': ->
    Session.set "showModal", false
    cb = Session.get "modalCallback"
    if cb
      cb(true)
}

The template it quite boring.

Here's my client code (as in the invoker of this helper):

Template.details.events {
  'click .remove': () ->
    showModal "YesNo", 
      "Are you sure you want to delete this item?", 
      "Deleting an items can't be undone. Are you sure you want to delete?", 
      (response) =>
        if response
          Items.remove this._id, (err) =>
            if err
              showModal "Error", "Error removing item", err.reason

    return false;
}

I can't get it execute the callback. All of the examples I've seen end up putting everything into the session, but apparently it can't convert the function to json so it doesn't deserialise it correctly when a user clicks on the ok or cancel buttons.

How can I execute a callback when a user responds to my modal?

Upvotes: 0

Views: 1877

Answers (2)

Pallavi Anderson
Pallavi Anderson

Reputation: 399

The Parties example demonstrates another pattern, which I like. Use a session variable to show/hide the dialog/modal, and put the callback in a Template event handler.

For example, see the inviteDialog template here: https://github.com/meteor/meteor/blob/master/examples/parties/client/parties.html#L194

This session variable controls its visibility: https://github.com/meteor/meteor/blob/master/examples/parties/client/parties.html#L15

This is a callback: https://github.com/meteor/meteor/blob/master/examples/parties/client/client.js#L257

Upvotes: 2

Tom Coleman
Tom Coleman

Reputation: 3037

I think the problem with the code you have there is that the variable modalCallback is local to the function (this is coffeescript, after all).

However, as you probably realise, this approach isn't really the right way to do it. The problem is that because the callback isn't being saved anywhere beyond a global variable, it will get lost in the case of a hot code push. (i.e. try hitting save on a file in your meteor project whilst the dialog is open, and see what happens when you subsequently close it).

This is actually a really good question, and I've been thinking a lot about the best approach. The best answer I have right now is to use a global reactive callback. Something like this:

Meteor.autorun(function() {
  if (Session.equals('lastDialog', 'alert-dialog') && 
      Session.equals('dialogOpen', false) && 
      Session.equals('lastDialogSuccess', true)) {
    alert("I'm alerting");

    // ensure it doesn't happen again, e.g. on another HCP
    Session.set('lastDialog', null);
  }
});

That code needs to be at the top level, so it re-runs on HCP. Take a look at this project I've set up to try and figure out a better way to do it: https://github.com/tmeasday/dialog-experiment/tree/global-reactivity

Perhaps a better answer is 'do things differently, in a more declarative/reactive way'. I'm not sure.

Upvotes: 0

Related Questions