This could be encapsulated somewhat nicer through a more low-level handling of content blocks. Anyway, hereās a preliminary sketch for getting started. It uses the packages template-extension
(for hooks and parent()
method) and template-var
.
First, the layout file should include a dimmer template:
<template name="appDimmer">
<div class="ui dimmer modals page"></div>
</template>
Optionally, a reference to the dimmer view is saved in the global namespace (or some place more clever):
Template.appDimmer.hooks({
rendered: function () {
// Save reference to this view in global namespace
appDimmer = this;
}
});
When a new route is triggered, all open modals should be closed:
Router.configure({
onBeforeAction: function () {
if (Meteor.isClient) {
// Hide active modals using the jQuery method from Semantic UI
if (typeof appDimmer !== "undefined")
$(appDimmer.firstNode).children().modal("hide");
}
this.next();
}
});
Each specific modalās content is wrapped in a custom block helper that takes care of the Semantic UI logic for showing and closing the modal, which looks like this:
<template name="appModal">
<aside class="ui small modal">
{{> Template.contentBlock}}
</aside>
</template>
Template.appModal.hooks({
rendered: function () {
var parent_view = this.view.parentView,
modal = $(this.firstNode);
modal.modal({
detachable: false,
onApprove: function () {
// Modals are closed manually after successful operation
return false;
},
onHidden: function () {
// Completely remove modal view after hide transition
Blaze.remove(parent_view);
}
});
// Show modal immediately upon rendering the template
modal.modal("show");
}
});
Each modal is rendered programmatically as the result of some event. The parent template where the event is triggered may have a template variable set up with some value that can be reached by the child modal:
<template name="appMyPage">
<section class="ui segment">
...
<button id="app-my-action-modal-show" class="ui positive right labeled icon button"><i class="send icon"></i>{{_ 'send'}}...</button>
</section>
</template>
Template.appMyPage.hooks({
created: function () {
TemplateVar.set(this, "value", 42);
}
});
Template.appMyPage.events({
"click #app-my-action-modal-show": function (event, template) {
// (template, context, DOM parent, view parent)
Blaze.renderWithData(Template.appMyActionModal, this, appDimmer.firstNode, template.view);
}
});
The actual modal template might look like this:
<template name="appMyActionModal">
{{#appModal}}
<div class="content">
<form id="app-my-action-form" class="ui form">
<input type="number" value="{{value}}">
</form>
</div>
<div class="actions">
<button class="ui black deny button">{{_ 'cancel'}}</button>
<button form="app-my-action-form" class="ui positive right labeled icon approve button"><i class="send icon"></i>{{_ 'send'}}</button>
</div>
{{/appModal}}
</template>
With a reactive value from the parent template as well as the event that may close the modal after a remote method call:
Template.appMyActionModal.helpers({
value: function () {
return TemplateVar.get(Template.instance().parent(), "value");
}
});
Template.appMyActionModal.events({
"submit #app-my-action-form": function (event, template) {
event.preventDefault();
var input = template.$("input"),
form = $(event.target).addClass("loading");
// The modal view has been opened with the same data context as the parent view,
// so this._id could be a relevant thing to send
Meteor.call("myAction", this._id, input.val(), function (error, result) {
form.removeClass("loading");
// The view is destroyed through the onHidden hook
if (!error)
$(template.firstNode).modal("hide");
// Alternatively, an error could be shown inside the modal box
});
}
});
Youāre welcome to get back to me with improvements or questions ā thanks 