Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subscribing to an empty list returns an object rather than an empty array #32

Closed
remaininlight opened this issue Nov 18, 2015 · 1 comment
Labels

Comments

@remaininlight
Copy link

For example:

var shrubs =ds.record.getList('shrubs');
*wait a bit, or wrap in .whenReady()*
shrubs.subscribe(function(shrubEntries) { console.log('shrubEntries', shrubEntries) }, true);

Produces an empty object rather than an empty array:
shrubEntries Object {}

Digging into the Record code which backs a List I tried initially setting this._$data to [] but it seems to be overwritten in the _onRead handler here:
https://github.com/hoxton-one/deepstream.io-client-js/blob/master/src/record/record.js#L347

I don't understand why a message reading the record is setting its data, or am I misinterpreting something?

What I would like to be able to do (for a potentially new list 'shrubs') is:

ds.record.getList('shrubs').subscribe(function(shrubEntries) { console.log('shrubEntries', shrubEntries) }, true);

But this doesn't log anything unless the subscribe is separated and wrapped in a .whenReady().

The way I'm using deepstream at the moment I was hoping to rely on an empty array turning up, to tell the application that the data has loaded but there is nothing there, so that ie. a loading spinner can be replaced with a blank list. Are there any situations where you would pass true to subscribe's triggerNow and not want an initial subscription?

I know I can wrap things in .whenReady() but I'm not sure why you wouldn't want this behaviour as default if you have passed true to triggerNow.

Thanks for open sourcing this excellent framework, I have been enjoying experimenting with it.

@yasserf
Copy link
Contributor

yasserf commented Nov 18, 2015

Thanks for the feedback, much appreciated!

I'll divide your questions into a few parts, they are also ordered a bit different to in your question.

I don't understand why a message reading the record is setting its data, or am I misinterpreting something?

When a record is requested from deepstream it tries to load its current state, and if the record doesn't exist will create it as an empty object and return that value.

Once that value is retrieved it will then fire the whenReady event, which means the record has set its data to be in sync with what the server has and you can start using it.

Since requesting the record the first time is an async operation, this._$data will be updated with the current state of the record from the server as soon as it is loaded, which is why it is being overriden on read events.

Produces an empty object rather than an empty array

The way lists work is they provide convenience APIs ontop of a normal record. This is to make it easier than having to deal with arrays directly and provide extra callbacks.

What you raised is actually a bug in the API where it exposes the default record content when it's first created ( which is an empty object ).

The method getEntries could instead be used to return an array instead so your code would look like this:

var shrubs =ds.record.getList('shrubs');
*wait a bit, or wrap in .whenReady()*
shrubs.subscribe(function(shrubEntries) { console.log('shrubEntries', shrubs.getEntries() ) }, true);
Doesn't log anything unless the subscribe is separated and wrapped in a .whenReady()

This is intended behaviour, since no events are actually fired until the isReady event occurs.

In your example:

ds.record.getList('shrubs').subscribe(function(shrubEntries) { console.log('shrubEntries', shrubEntries) }, true);

Since shrubEntries is not yet loaded from the server, you can't actually be told what the current state is.

By putting it in whenReady:

ds.record.getList('shrubs').whenReady( function() {
    subscribe(function(shrubEntries) { console.log('shrubEntries', shrubEntries) }, true);
} );

It's now saying that as soon as the information is loaded from the server ( its initial state ) subscribe to the any changes and be told what the initial value is.

In your case of finding out if it's loaded or not would be:

// Set Default Loading Behaviour
var list = ds.record.getList('shrubs');
list.whenReady( function() {
    subscribe( function( shrubEntries ) { 
        var shrubEntries = list.getEntries();
    }, true);
        // Remove loading behaviour ( this should only be triggered once during the list lifetime )
} );

Normally, using records, you won't need to use closures, but given the issue mentioned in part 2 the record is still exposed in a few callbacks instead of the list. Raised #33 as well to capture that.

Hope this helps, and feel free to let me know if something doesn't make sense!

@yasserf yasserf added the bug label Nov 18, 2015
WolframHempel added a commit that referenced this issue Dec 14, 2015
Fixes #32 Subscribing to empty list returns object instead of array
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants