Horizon

The Horizon object instantiates and manages the connection to the Horizon server.

// connect to the Horizon server, after Horizon has been loaded via
// <script> tag or require
const hz = new Horizon();

Horizon constructor arguments

All arguments are optional. Pass them to Horizon in an object with option keys: {secure: true}.

Lazy writes

When lazyWrites is set to true, Horizon queries that modify a Collection will not perform their writes when the query is first executed, but instead perform then when the Observable returned by the query is iterated through.

const hz = new Horizon({lazyWrites: true});

// because lazyWrites is set, nothing is sent to the server here...
var query = messages.store([
    {
        from: "agatha",
        text: "Meet at Smugglers' Cove on Saturday"
    },
    {
        from: "bob",
        text: "Would Superman lose a fight against Wonder Woman?"
    }
]);

// ...but instead, writes are performed here
query.subscribe(uuid => {
    console.log('Document ${uuid} was created.');
});

A Horizon object can be called as a function, taking a string as its argument. It returns a Collection object:

// Return the messages Collection
const messages = hz('messages');

Methods

Horizon.connect

Establish a Horizon connection.

Note that you can create a Collection from the Horizon instance without calling connect() first. Once you start using the collection, the connection will be automatically established.

const hz = new Horizon();

// Get access to the messages collection
const messages = hz('messages');

// Start establishing the Horizon connection.
// This step is optional. We can skip it and go directly to the next line.
hz.connect();

// Start using the collection
messages.store({ msg: 'Hello World!' });

Horizon.disconnect

Close a Horizon connection.

Horizon.status

Receive status updates about the connection to the Horizon server.

Calling status() without any arguments returns an RxJS Observable. Alternatively you can pass in a callback to execute when the status of the connection changes. Any arguments passed to status() will be treated as if passed to Observable.subscribe(args...).

The emitted status objects can be one of the following:

Horizon.onReady

Similar to Horizon.status(), but only emits { type: 'ready' } events.

Horizon.onDisconnected

Similar to Horizon.status(), but only emits { type: 'disconnected' } events.

Horizon.onSocketError

Similar to Horizon.status(), but only emits { type: 'error' } events.

Horizon.hasAuthToken

Check if the user has a valid authorization token (i.e., has logged in).

See Authentication for more details.

Horizon.currentUser

Returns a query for the current user, that you can run by calling either watch() or fetch().

The query result is a user object as described in Users and groups, or an empty object if the user is unauthenticated.

const hz = new Horizon();
hz.currentUser().fetch().subscribe( (user) => console.log(JSON.stringify(user)) );

currentUser() requires read permissions on the user’s document in the "users" collection. The following rule enables the required permissions:

[groups.default.rules.read_current_user]
template = "collection('users').find({id: userId()})"

See Permissions for more information on how to configure access rules, and Authentication to find out how to configure user authentication on the Horizon server.

Horizon.authEndpoint

Return a previously-configured OAuth endpoint.

See Authentication for more details.

Horizon.clearAuthTokens

Clear authentication tokens from local storage.

Horizon.clearAuthTokens();

See Authentication for more details.

Horizon.aggregate

Combine the results of multiple Horizon queries into one result set.

const hz = new Horizon();

var userId = 100;
hz.aggregate({
    userId: userId,
    user: hz('users').find(userId),
    activity: {
        posts: hz('posts').findAll({user: userId}),
        topComments: hz('comments').findAll({user: userId}).order('rating', 'descending').limit(10)
    }
}).watch().subscribe(subscribeFunction);

(In real code, subscribe() would contain a callback function to receive the Observable results from watch().)

The values for fields in aggregates may contain:

Observables inside an aggregate are called when the aggregate is subscribed to, and behave identically whether the aggregate is called with fetch() or watch(). So an aggregate such as the following:

hz.aggregate({
    counter: Observable.timer(0, 1000),
    result: hz('foo').find('bar')
}).watch().subscribe({ next(x) { console.log(x) }});

will be emitted every time the document in the result query is changed and every time the counter is incremented.

Arrays are not flattened. A field/value such as dogShow: [hz('owners'), hz('pets')] will result in output similar to [['bob', 'agatha', ...], ['fluffy', 'fido', ...]]. (Use merge() for a union query.)

Aggregates can be nested, although this is equivalent to simply using objects for the “inner” aggregates.

/// this...
hz.aggregate({
    foo: hz.aggregate({ ... })
});

// ...is equivalent to this
hz.aggregate({
    foo: { ... }
});

Horizon.model

Create a template for aggregates, using parameters.

The aggregate example could be rewritten with model this way:

const hz = new Horizon();

const userModel = hz.model((userId) => {
    return {
        userId: userId,
        user: horizon('users').find(userId),
        activity: {
            posts: horizon('posts').findAll({user: userId}),
            topComments: horizon('comments').findAll({user: userId}).order('rating', 'descending').limit(10)
        }
    }
});

userModel(100).watch().subscribe(subscribeFunction);

You can do anything with model that you can do with aggregate, including nesting models.