调用方法

时间:2015-07-11 14:48:24

标签: javascript node.js mongodb meteor

有人可以向我解释为什么当我在路由器中有集合代码时会导致在调用方法时调用路由吗?

考虑以下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);
    }
});

问题在于,如果我在表单上按提交,则在调用该方法之后,即使e.preventDefault()出现,路由器也会激活。控制台日志清楚地显示了这种行为:

"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

此外,您可以看到路由器被调用两次,并且它永远不会进入Template.home.rendered。这会导致加载div出现并且永不离开。我可以确认数据是否正确插入。

但是,如果我删除routes.js中的collection.findOne(),则此行为将消失,一切都按预期工作。

问题

  • 为什么只有在路由中有collection.findOne()时才会调用路由?

  • 为什么collection.findOne({ test: 'somevalue' })永远不会在路线内返回任何内容? (我知道如何通过在script.js中使用Session变量和帮助器来解决这个问题,但我想确切知道原因)

这会在我的应用中造成很多意外行为。非常感谢你提前。

2 个答案:

答案 0 :(得分:2)

正如其他人所回答的那样,问题来自Meteor将反应性地重新运行在被动上下文中运行的代码,当且仅当该代码发出对被动数据源的调用时。

在您的情况下,对findOne的调用是对被动数据源的调用,Router.route('/', function () { // context });中的上下文是被动上下文。

有两个重要的工具可以让你控制这种行为:一个是好的设计。注意反应性并尝试围绕它设计代码。 另一个是检查Tracker.active并使用Tracker.nonreactive来避免反应数据上下文中的反应。

这应该回答你的第一个问题。至于为什么你的findOne查询永远找不到任何东西:你是否已将数据从服务器发布到客户端?请查看Publish-Subscribe。你基本上需要:

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

答案 1 :(得分:0)

每次在运行查询的数据库上保存文本时,对路径内的collection.findOne()的调用都会侦听数据库上的任何新更改。

可能的解决方案: 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();
  }
});

服务器/ publish.js上的发布文件

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

我希望这可以帮助您解决问题。 最好的。