This API is deprecated and will be turned down in January 2019. Migrate to Cloud Firestore or another data store as soon as possible to avoid disruptions to your application.

Custom collaborative objects

Custom collaborative objects allow you to add realtime collaboration features to an existing JavaScript object type. These custom objects can be added to the collaborative data model just like the built-in collaborative object types, and registered collaborative fields are automatically synced across users.

Registering custom types and fields

To use custom objects, you must first register your custom object type before loading a document. This typically occurs at model initialization time. See model lifecycle.

To illustrate how this works, consider an example custom class named Book.

myApp.Book = function() {}

Register this class with the registerType method:

gapi.drive.realtime.custom.registerType(myApp.Book, 'Book');

Now that the class is registered, you can add collaborative fields. These fields support normal read/write operations just like a regular field. However, when you write to the field, the new value is automatically saved in the realtime model and sent to other collaborators as an event.

Since this class is a book, you can add fields that describe books:

myApp.Book.prototype.title = gapi.drive.realtime.custom.collaborativeField('title');
myApp.Book.prototype.author = gapi.drive.realtime.custom.collaborativeField('author');
myApp.Book.prototype.isbn = gapi.drive.realtime.custom.collaborativeField('isbn');
myApp.Book.prototype.isCheckedOut = gapi.drive.realtime.custom.collaborativeField('isCheckedOut');
myApp.Book.prototype.reviews = gapi.drive.realtime.custom.collaborativeField('reviews');

Once the document has been loaded, you can create instances of the custom object by calling model.create with either the class or the string name used to register the type. For example you could write:

var book = model.create(myApp.Book);

or

var book = model.create('Book');

After creating the Book object, you can now assign it to an object in the hierarchy (in this case, the root) as follows:

model.getRoot().set('book', book);

Like the pre-defined collaborative objects, you can add an event listener to be notified of changes. Custom objects emit VALUE_CHANGED events.

book.addEventListener(gapi.drive.realtime.EventType.VALUE_CHANGED, doValueChanged);

To assign values to the fields in the book object, assign them as you would any other object. For instance, to create the book "Moby Dick", you would set the fields:

book.title = 'Moby Dick';
book.author = 'Melville, Herman';
book.isbn = '978-1470178192';
book.isCheckedOut = false;

Lifecycle of a custom collaborative object

There are some important differences between the lifecycle of a standard object and a collaborative object. In a traditional data model object, the object's constructor is called exactly once in the object's lifetime. Initial data values are usually set by passing them into the object constructor.

Collaborative objects work a little differently. A collaborative object exists on multiple computers at once, and is reconstructed each time a document is loaded. A collaborative object's constructor may be called many, many times over the object's lifetime. Because of this, initial collaborative data values for newly-created objects must not be set in the object's constructor.

In fact, initial data values can't be set in the object's constructor, because the collaborative object isn't even wired up to the Realtime API's collaboration technology until after it's constructed. Thus, the constructor of a custom collaborative object can only be used to set up the non-collaborative object state, like local caches. Most custom collaborative objects should have empty constructors.

In custom collaborative objects, initial state is set up via the initializer and the onLoaded hook.

The initializer hook

A custom object may specify an initializer method using the setInitializer method:

gapi.drive.realtime.custom.setInitializer(myApp.Book, doInitialize);

The initializer is called exactly once in the lifetime of an object, immediately after the object is first created. When that object is reloaded in the future, the initializer is not executed; instead, the object is populated by loading saved data from the server. Initializer methods may take parameters, so the initial object state can be set up at creation time.

Imagine extending the book example so that each book contains a collaborative list of reviews (it's a collaborative book, after all). You have already created a collaborative field for the list of reviews, but that collaborative field doesn't have an initial value specified yet. The list of reviews needs to be available in every book object, as soon as it's created, so you need to create that list in the object initializer.

function doInitialize(opt_title) {
  var model = gapi.drive.realtime.custom.getModel(this);
  if (opt_title) {
    this.title = opt_title;
  }
  this.reviews = model.createList();
}

Notice that the initializer can have parameters. You can pass parameters into the initializer via model.create():

// Create a book with a default title.
model.create(myApp.Book, 'Paradise Lost');

Now add accessor methods for our list of reviews:

myApp.Book.prototype.addReview = function(review) {
  this.reviews.push(review);
  console.log('Review added locally. Current review count: ' +
      this.reviews.length);
};

myApp.Book.prototype.getReviews = function() {
  return this.reviews.toArray();
};

The onLoaded hook

To run code every time that an object's initial data becomes available, you need an onLoaded hook.

Sometimes, it's necessary to take some action once an object's initial data is populated. In a traditional data model object, this kind of thing is often done in the object constructor, but that won't work for a collaborative object. This setup also can't be done in the initializer, because the initializer only gets called once. Collaborative data model objects do this with an onLoaded hook.

For example, maybe you want to write a local logging message every time a book's review list is modified.

gapi.drive.realtime.custom.setOnLoaded(myApp.Book, doOnLoaded);

Now, you can write our logging code, secure in the knowledge that any collaborative fields that were set in the object's initializer will be populated with data:

doOnLoaded() {
  // Note that "this" is the newly created object, even though
  // this method is statically defined. The onLoaded event is
  // always called in the context of the loaded object.
  this.addEventListener(gapi.drive.realtime.EventType.OBJECT_CHANGED,
      logReviewChange);
}

Enviar comentarios sobre…