【问题标题】:Invoke Meteor method only on the client仅在客户端调用 Meteor 方法
【发布时间】:2016-04-17 20:38:58
【问题描述】:

有没有办法告诉Meteor.callMeteor.apply 只运行客户端存根而不调用服务器方法?

假设我们有待办事项列表示例。也许我们想向匿名(未登录)用户显示一些默认任务:

  • 尝试检查任务
  • 重命名一个
  • 添加您自己的
  • 创建帐户

登录的用户应该看到他们的任务,我们不希望两次实现所有功能(一次用于注册用户,一次用于匿名用户)。

如果以正常方式实现,Meteor 会将更改推送到所有连接的客户端,这意味着所有匿名用户将共享相同的任务并实时查看其他人的编辑。

为每个匿名用户添加自己的任务会使数据库充满无用的东西。

所以我正在寻找一种只在客户端运行方法的方法if (!Meteor.user())

【问题讨论】:

  • 为什么要这么复杂,为什么不直接创建你想要的函数,直接调用呢?您仍然可以在方法存根中使用相同的函数以保持一致性。
  • 什么意思?该界面呈现 Tasks 集合。 Tasks 集合在服务器上更新并下推到客户端。 “创建函数 […] 并直接调用它”是什么意思?我将创建哪个功能?怎么直接调用?

标签: meteor


【解决方案1】:

对此有不同的方法:

只需将这些待办事项添加到数据库中(无论如何)。

这是最简单的方法,因为您不会向您的应用添加任何额外的逻辑(除了在匿名登录您的应用时向您的应用添加数据)。

您说它会“用无用的东西填充数据库”,但这真的重要吗?莎士比亚全集大约有 5MB,你可能不会有任何问题。

如果您采用这种方式,您可能需要添加一个匿名帐户系统,以引用哪个用户拥有哪些项目。我会推荐artwells:accounts-guest 包,但还有其他一些。

使用仅限客户端的集合。

DummyTodos = new Mongo.Collection('dummy-todos');

您要确保此代码仅在客户端运行,因此:

  • if(Meteor.isClient)包围它;
  • 或将其放入/your-root-project/client 文件夹中的文件中。

但是你必须在所有处理待办事项的地方添加更多逻辑:

    Meteor.methods({
      'todo.setChecked'(todoId, isChecked) {
        check(todoId, String);
        check(isChecked, Boolean);
            var todo = Todos.findOne(todoId);
            var todoClass = Todos;

            if(!todo && Meteor.isClient){
                todo = DummyTodos.findOne(todoId);
                todoClass = DummyTodos
            }

            if(todo) {
                todoClass.update(todoId, { $set: { checked: isChecked } });
            } else if(Meteor.isClient){
                // On the server side, you don't know whether something went wrong, or it was just a local todo
                // So you're losing some error handling here, which isn't good

                // You can still deal with this on the client-side, maybe you want to:
                throw "No todo with id " + todoId;
                // or just
                return;
                // But the server will fail silently, so you're losing error handling
            }

      },
    });

你可以看到有更多的逻辑,你可以把它包装在一个函数中,比如:

    var getTodoOrDummyTodo: function(todoId) {
        var todo = Todos.findOne(todoId);

        if(!todo && Meteor.isClient){
            todo = DummyTodos.findOne(todoId);
        }

        // I return some todo, but I don't know where it comes from
        if(todo)
            return todo;
        else
            throw "Well, something wrong happened but I'm not sure what"
    }

但是您看到还有其他问题(您不知道待办事项来自哪里,您无法控制服务器端,...)。您还可以标记待办事项(添加“isDummy”字段,例如:

    Meteor.methods({
      'todo.setChecked'(todoId, isChecked) {

但同样,这意味着您必须到处查看此标志。这不是未来的证据

使用普通的 javascript 对象和函数

我认为这是@christian-fritz 在 cmets 中针对您的问题提出的建议。您可以使用纯 javascript 对象,并将它们与您的集合合并:

    var dummyTodos = [
        {text: "Hello", checked: true},
        {text: "Bye", checked: false}
    ]

    var todos = Todos.find();
    if(todos.count() < 1){
        return dummyTodos;
    } else {
        return todos;
    }

在您的 Meteor 方法中,您可以直接发送 todo 对象,检查是否有 _id 字段,并相应地更新它,如下所示(简化):

    Meteor.methods({
      'todo.setChecked'(todoObject, isChecked) {
        // Do the checks
        if(todoObject._id){
            Todos.update(todoObject._id, { $set: { checked: isChecked } });
        } else {
            todoObject.checked = isChecked;
        }

但是你会失去集合和模板的反应性(你可以自己实现,使用Tracker Dependency,但同样,这不是最简单的方法)。

TL;DR:这些示例说明了为什么为相似的对象拥有两个不同的数据存储是一个坏主意,特别是如果它们具有不同的 API,并且您无法创建“模拟”类似于 mongo 集合对象的集合。如果“待办事项”在您的应用程序中不是一个重要对象,您可以使用替代方案,就像我展示的那样,但在这里可能会在您的整个应用程序中增加 10% 的代码,如果不是更多的话。所以使用服务器端收集。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-19
    • 1970-01-01
    • 2022-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多