在Backbone js中永久引用另一个数据

时间:2015-01-04 18:07:22

标签: javascript rest authentication backbone.js mongoose

我使用Backbone创建了一个用户可以与内容(书签,星标等)进行交互的网站,我想要一种方法来存储用户在用户数据中与之交互的内容。很简单,但我在这里寻找有关最佳方法的信息。

我已经构建了一个没有用户帐户的原型(数据被加载到localStorage中),因此内容本身现在存储用户交互(在该内容的元数据中),但是要在一个用户帐户中打开多个用户。时间,我想更改它,以便用户保存一段内容后,该内容的ID(或永久性内容)将被保存到用户帐户数据中。

我目前正在使用localStorage适配器并在页面加载时加载内容,但使用Backbone时,模型的ID每次都会更改。一旦我转移到带有用户帐户的REST数据库,我就不确定如何保存用户在其帐户详细信息对象中与之交互的内容,并且能够在UI中可靠地使用该内容。

任何帮助我指向正确方向的帮助都会很棒。其他人如何解决这个问题?定制uid?来自db的id?

谢谢,

1 个答案:

答案 0 :(得分:1)

更新:在与OP的私人对话中,他解释说他需要在各种设备中显示该网站的多个实例,以便为登录用户显示一致的用户数据(即用户偏好应反映在所有设备)。为了在客户端和服务器之间保持新的链接,OP将使用socket.io。

解决方案概述

在这种情况下,基本上会传递三种类型的数据。网站内容数据将显示为单个视图。用于识别用户的服务器的用户配置文件数据;基本上是唯一的用户ID(UID)。最后,反映用户书签(加星标)的conent的数据。

面临的挑战是在给定用户的所有并发会话中保持用户选择数据的新鲜度。我将在下面描述的想法将解释如何在所有三个数据源之间建立通信链接,以便动态数据(用户选择)可以保持并立即刷新。为此,我们将使用Backbone的事件聚合器,以及Backbone视图和模型提供的封装。

数据库结构

反映三组数据,数据库应设计有三个表:User Profile表,Content表和User Content查找表。架构应该如下所示,

                     User Profile                         Content
       ---------------------------------------   --------------------------
       | UID | Username | First | Last | ... |   | ID | Title| Date | ... |
       ---------------------------------------   --------------------------

                                User Content Lookup 
                                   ------------
                                   | UID | ID | 
                                   ------------

前端设计

我们必须设置三种类型的Backbone对象来处理数据循环。用于实例化用户prefrences对象的用户视图。用于处理事件委派和项呈现的每个内容项的视图。还有一个Backbone集合对象,它将充当控制器,具有持久化和获取数据的逻辑。为了让每个人都能说话,我们将安装一个具有本地范围的事件聚合器,所有这些视图都可以订阅和发布。

用户和内容视图

用户视图是一个vanilla Backbone视图。从图形上看,它只提供登录/注销,帐户配置文件等链接。它也是用户配置文件数据的存储库,它将模型存储在其中。我们关心的是它1.具有用户的唯一ID,并且2.将使用该UID实例化控制器对象。

// We set up the user model to initialize the 
// controller when the data has been fetched
var UserModel = Backbone.Model.extend({
  initialize: function(options) {
    this.controller= options.controller; // A reference to the controller is passed
                                         // in before we instantiate the model
    _.bindAll(this, "initializeController"); // Ensures proper context
    this.listenTo(this, "add", this.initializeController);
  },

  initializeController: function () {
    this.controller.fetch({ id: this.get('UID') });
  },
}); 

// We fetch the user data, which, when it comes in, initialized the
// user's ID
var usrModel = new UserModel({ controller: appController });
usrModel.fetch();

每个内容行都有自己的视图。当用户与该内容项交互时,这允许简单的事件管理。每个视图都会将自己的ID与描述交互的事件一起发送给控制器。相反,如果用户在单独的并发会话中选择或取消选择视图,控制器可以发送提醒它的视图事件。

// We wire the star event
initialize: function() {
  _.bindAll(this, "checkItem", "uncheckItem", "onClickStar");
  // Listen to items that have changed in a concurrent session
  this.listenTo(App.vent, "new:item:selected", this.checkItem);
  this.listenTo(App.vent, "new:item:unselected", this.uncheckItem);
},

events: {
  "click .star": "onClickStar"
},

onClickStar: function () {
  // we check if the star has been checked or unchecked
  // Here you can roll your own, depending on your implementation (e.g. checkbox)
  if (checked)
   App.vent.trigger("item:selected", this.model.get('ID'));
  else
   App.vent.trigger("item:unselected", this.model.get('ID'));
},

checkItem: function (id) {
  if (this.model.get('ID') == id)
    // find the check item and check it (without using click)
},

uncheckItem: function (id) {
  if (this.model.get('ID') == id)
    // find the check item and uncheck it (without using click)
}

关键是在触发器上发送ID,因此监听触发器的控制器知道add / remove的内容。

控制器

控制器本身就是操作的大脑。以下是我们订阅内容项更改,并在后端传播这些更改,我们在后端监听更改并将其发布到视图。在这里,我们也设置了与内容事件交互的socket.io绑定。

// Let's define the controller collection object
// The controller has to defined AND instantitated BEFORE 
// the user model object, so that it can pass a reference to
// itself to the user model
var Controller = Backbone.Collection.extend({
  initialize: function () {
    _.bindAll(this, "socketIni");
    this.socketIni();
  },

  // We override fetch to pass in the id we need for the fetch route
  fetch: function(options) {
    this.url = "/user/" + options.id + "/content";
    return Backbone.Collection.prototype.fetch.call(this, options);
  },

  socketIni: function() {
    var socket = io();
    this.listenTo(App.vent, "item:selected", function (id) {
      // When a check is added, socket emits the id and event
      socket.emit('item added', id);
    });
    this.listenTo(App.vent, "item:unselected", function (id) {
      // When a check is removed, socket emits the id and event
      socket.emit('item removed', id);
    });

    // Set up socket to let the content views when something changes in the db
    socket.on('new item selected', function(id) {
      App.vent.trigger('new:item:selected', id);
    });
    socket.on('new item unselected', function(id) {
      App.vent.trigger('new:item:unselected', id);
    });
  },
});

// We instantiate the controller that we passed in to usrModel
// REMEMBER: This must be done BEFORE you construct userModel.
vet appController = new Controller();

上面的代码可能并不完美,但它展示了如何在多个并发会话中保持大量视图的基本思路。