Nelson Yeung
Nelson Yeung

Reputation: 3402

Meteor entering route when calling a method

Can someone explain to me why when I have collections code inside router will cause the route to be called when a method is called?

Consider the following code:

home.html

<template name="home">
    {{ duplicate }}
    <form>
        <input type="text" name="test" value="somevalue">
        <input type="submit" value="Submit">
    </form>
</template>

script.js

Template.home.events({
    'submit form': function (e) {
        e.preventDefault();
        console.log('Enter Meteor call');
        Meteor.call('createDoc', { 'test': e.target.test.value });
    }
});

route.js

Router.onBeforeAction(function () {
    console.log('Enter onBeforeAction');
    $('#loading').show();
    this.next();
});

Router.route('/', function () {
    console.log('Enter action');
    var foo = collection.findOne({ test: 'somevalue' }) ? 'true' : 'false';
    this.render('home', {
        data: {
            'duplicate' : foo
        }
    });

    Template.home.rendered = function () {
        console.log('Enter rendered');
        $('#loading').hide();
    };
});

methods.js

collection = new Mongo.Collection('collection');

Meteor.methods({
    createDoc: function (data) {
        console.log('Enter createDoc');
        collection.insert(data);
    }
});

The problem is that if I press submit on the form, after the method is called the router will activate, even though e.preventDefault() presents. The console log shows this behaviour clearly:

"Enter Meteor call" script.js:4:3
"Enter createDoc" methods.js:5:3
"Enter onBeforeAction" routes.js:2:2
"Enter action" routes.js:8:2
"Enter onBeforeAction" routes.js:2:2
"Enter action" routes.js:8:2

Furthermore, you can see that the router is called twice and that it never enters Template.home.rendered. This causes the loading div to appear and never leaves. I can confirm that data are being inserted correctly.

If I remove collection.findOne() in routes.js, however, this behaviour will disappear and everything works as expected.

Questions

This is causing a lot of unexpected behaviour in my app. Thank you very much in advance.

Upvotes: 3

Views: 434

Answers (2)

B M
B M

Reputation: 4019

As answered by others the problem you have arises from the fact that Meteor will reactively re-run code that runs in a reactive context, if and only if, that code issues a call to a reactive data source.

In your case, the call to findOne is a call to a reactive data source and the context in Router.route('/', function () { // context }); is a reactive context.

There are two important tools that let you control this behavior: one is good design. Be aware of the reactivity and try to design your code around it. The other is checking Tracker.active and using Tracker.nonreactive to avoid reactivity inside a reactive data context.

This should answer your first question. As to why your findOne query never finds anything: have you published the data from the server to the client? Please check out Publish-Subscribe. You basically need:

// on the server
Meteor.publish('myPublication', function(author) {
     return collection.find();
});
// on the client
Meteor.subscribe('myPublication');

Upvotes: 2

lfergon
lfergon

Reputation: 973

The call to collection.findOne() inside the route is listening to any new changes on the database, every time text is saved on the database the query is run.

A possible solution: Router.js

Router.onBeforeAction(function () {
  console.log('Enter onBeforeAction');
  $('#loading').show();
  this.next();
});



Router.route('/', {
  template: 'home',
  waitOn: function() {
    return Meteor.subscribe('collection');
  },
  data: function() {
    var foo = collection.findOne({ test: 'somevalue' }) ? 'true' : 'false';
    return {
        'duplicate': foo
    };
  },
  action: function() {
    this.render();
  }
});

And a publish file on server/publish.js

Meteor.publish('collection', function () {
  return collection.find();
});

I hope this can help you solving your problem. Best.

Upvotes: 0

Related Questions