1

I am trying to get modals to consistently work with Meteor. They have this problem of disappearing when data context values change. I've already solved a portion of this problem, as documented by this question, but now it's back, and it's happening when values in the surrounding template change, rather than values in the template.

Here's the actual modal:

<div class="modal fade" id="paymentModal" tabindex="-1" role="dialog" aria-labelledby="paymentModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">

            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                <h4 class="modal-title" id="paymentModalLabel">Make a Payment</h4>
            </div>

            <div class="modal-body">
                {{> paymentModalBody}}
            </div>

            <div class="modal-footer">
                {{> paymentModalFeedback}}
            </div>
        </div>
    </div>
</div>

The modal works fine when the values changing are inside of it (or in other words, when paymentModalBody or paymentModalFeedback have changing values, since those template re-renders don't cause the main modal elements to be re-rendered), but....

this is happening inside my userView template, which displays information about a user (duh). The modal handles payment interaction with the user, and calls a Meteor.method called...

makeBraintreePayment: function(saleObj) {
    var now = new Date();
    Gateway.transaction.sale(saleObj, Meteor.bindEnvironment(
        function (err, result) {
            if (result.success) {

                if (result.transaction.customer.id && saleObj.options.storeInVaultOnSuccess) {
                    Meteor.users.update(Meteor.userId(), {$set: { braintree_id: result.transaction.customer.id }});
                }

                var paymentId = Payments.insert({ ... });
                Meteor.users.update(Meteor.userId(), {$push: { 'payment_ids': paymentId }});

                return result.transaction.id;
            } else {
                throw new Meteor.Error(401, result.message);
            }
        },
        function(err) {
            console.log('bind failure: ' + err.message);
        }
    ));
}

now again, all of this works just fine, but, after the payment is made and the modal has displayed the success message, after a second or two the modal disappears and leaves only the background, locking out the user and making it necessary to refresh the page. Broken.

It's pretty clear to me that this is happening because of those Meteor.users.update calls, since they're changing the data context of the userView template, which is causing the modal template to be re-rendered. So, I tried to use preserve:

Template.userView.preserve(['#paymentModal', '.modal-dialog', '.modal-content', '.modal-header', '.modal-body', 'modal-footer', '.modal-title', '.close']);

and this:

Template.userView.preserve(['#paymentModal']);

Neither worked. This should be maintaining the html for all of the static modal elements, while allowing everything around it to be re-rendered, but it doesn't.

What's going on? How to I solve this?

Thanks in advance!

P.S.

I have been trying to solve this problem by using a more stable modal library, bootboxjs, but I've had a different problem with that. If you can offer some insight on either that would be awesome!

Community
  • 1
  • 1
blaineh
  • 2,263
  • 3
  • 28
  • 46

1 Answers1

1

Put your modal in an {{#isolate}} block as well.

{{#isolate}}
    <div class="modal fade" id="paymentModal" tabindex="-1" role="dialog" aria-
       ...
    </div>
{{/isolate}}

This way, if something changes outside it will be ignored as well as inside it.

Something better may be to consider upgrading to using the Blaze RC (running meteor --release blaze-rc1 update) which uses fine grained DOM patching to avoid this issue. And plays well with Bootstrap and other jquery plugins.

The difference is Spark (the current rendering engine) replaces the entire DOM when there is a change, where Blaze is designed to change only the element which has changed.

Tarang
  • 75,157
  • 39
  • 215
  • 276
  • Alright, the `{{#isolate}}` helper didn't work, so I've upgraded to Blaze and made template changes as required by [this page](https://github.com/meteor/meteor/wiki/Using-Blaze#conditional-attributes-with-no-value-eg-checked-selected), but now I'm getting this error `Uncaught ReferenceError: Spark is not defined `. I'm looking for this, and it seems to be related to the `{{loginButtons}}` helper, which I changed to `{{> loginButtons}}`, but still I'm getting the error. – blaineh Mar 17 '14 at 14:52
  • Well, it has something to do with `iron-router`. Do you know how to get iron-router to work with Blaze? – blaineh Mar 17 '14 at 14:55
  • And if getting things to cooperate is impossible, how can I go about reverting to Spark? – blaineh Mar 17 '14 at 15:05
  • 1
    To use blaze you need to set up your smart.json this way: https://github.com/tmeasday/iron-router-issue-478/blob/master/smart.json. To revert to spart just use --release 0.7.1.2. Imho Meteor 0.8 is going using Blaze it might be better to just change to it now. Also dont forget to go through the notes: http://www.meteorpedia.com/read/Blaze_Notes – Tarang Mar 17 '14 at 23:55