Reputation: 113
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
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
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