redress
redress

Reputation: 1449

Passing array via ReactiveVar in Meteor

I have a Meteor method that returns all user accounts on my application

returnUsers: function(){
    return Meteor.users.find().fetch();
}

I'm using new ReactiveVar to pass the return value of the Meteor method into my template helper:

Template.listViewTemplate.created = function (){
    var self = this;
    self.myAsyncValue = new ReactiveVar("Waiting for response from serv er...");
    Meteor.call('returnUsers', function (err, users) {
        if (err)
            console.log(err);
        else 
            self.myAsyncValue.set(users);
    });
}

Template.listViewTemplate.helpers({
    userCollection: function(){
        return Template.instance().myAsyncValue.get();
    }
});

But when I go to render the users into the view, I get a console error that reads

{{#each}} currently only accepts arrays

When I render without the #each iterator, using

<ul id='usersList'>
    {{userCollection}}
</ul>

the output on my web-page accurately reflects the number of users (2), but reads

[object Object],[object Object]

I'm pretty sure that there is some funkiness going on here because I'm using a global Meteor collection (Meteor.users.find().fetch(), as opposed to having defined my own collection), but I'm not sure how to get around it.

I want to display a list of all users so the current user can click another user and share a document with them--not sure how to get around this.

Upvotes: 1

Views: 3828

Answers (4)

raddevon
raddevon

Reputation: 3360

ReactiveVar doesn't like arrays. You could install the ReactiveArray package which should accomplish exactly what you want.

Update

Based on comment of mper

In the latest versions of Meteor you can put an array in a ReactiveVar.

Tested on

Upvotes: 2

mper
mper

Reputation: 301

I have several remarks about your question:

Do not fetch

You don't need .fetch() on your method. When you call find() on collections, such as Meteor.users a cursor is returned. The template (and #each in particular) can iterate through cursors. Cursors are usually better because you don't load the entire collection into memory at once - fetch does.

Meteor collections are reactive

Meteor collections are already reactive, meaning that if they change, they will trigger changes on your templates as well. So, you don't need to use a ReactiveVar to wrap your collection.

Query your local database

You don't need to use a method to get the users and in fact, you shouldn't, because usually you want to make queries to the database stored locally, not make calls to the server. Just call Meteor.users.find() directly in your template helper. You can (and should) control what is available locally through subscriptions.

Use #each with else

You can use the following in your template:

 {{#each userCollection}}
 ...
 {{else}}
 Waiting for response from server...
 {{/each}}

If userCollection is empty, the template will render the else block, just like you wanted.

Summarizing

Delete your method and onCreated with everything inside, change whatever is inside your template helper to only return Meteor.users.find() and use {{#each userCollection}}...{{else}}Waiting for response from server...{{/else}}

By the way

In the latest versions of Meteor you can put an array in a ReactiveVar.

Upvotes: 1

Abhi Aiyer
Abhi Aiyer

Reputation: 21

Template.onCreated(function(){}) only gets run once and meteor methods only run once

You need reactivity here.

Collections sre reactive meaning pub/sub.

You need to create a publish function that allows certain users to fetch other users in the database. So all uses with maybe if the currentUser has permission to read all user info. Id limit the fields too.

Upvotes: -1

M&#225;rio
M&#225;rio

Reputation: 1612

You don't need to use a reactive variable for this. The function at Template.listViewTemplate.created is not container in an autorun, which means: It won't get recomputed.

The best approach for your scenario is: Use a variable to get the status ( loading, loaded, error) and another variable to save the array itself attach to self. Reactivity is cool but you should only use it when needed.

About:

[object Object],[object Object]

This is happening because you're not extracting any value form the object provided nor looping using {{#each}}.

Your solutions for listing users is dangerous and inefficient. You're sending to the client all the fields from the user collection, including login tokens.

The best approach is to create a subscription that send only the necessaries fields like: _id, info.firstName. You should also have some criteria to the list users and use pagination. Consider also a search feature for such purpose.

Upvotes: 2

Related Questions