仅在客户端

时间:2016-04-16 20:08:12

标签: meteor

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

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

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

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

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

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

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

1 个答案:

答案 0 :(得分:0)

有不同的方法:

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

这是最简单的方法,因为您无法在应用中添加任何其他逻辑(除非在匿名登录您的应用时向您的应用添加数据)。

你说它会用无用的东西填充数据库"但它真的重要吗?莎士比亚的全部作品重约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"
    }

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

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

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

使用普通的javascript对象和函数

我认为这是@ christian-fritz在你的问题评论中提出的建议。您可以使用普通的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方法中,您可以直接发送待办事项对象,检查是否有_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,并且您不能创建一个&#34; mock&#34;集合的类似于mongo集合对象。如果&#34; todos&#34;在你的应用程序中不是一个重要的对象,你可以使用替代方案,就像我已经展示的那样,但是这里可能会在你的整个应用程序中增加10%的代码,如果不是更多的话。所以使用服务器端集合。