fraherm
fraherm

Reputation: 691

Meteor.js: Client doesn't subscribe to collection

I created a little example for myself to test some stuff with Meteor. But right now it looks like I can't subscribe to a collection, I published on the server side. I hope somebody can tell me where the bug is.

server/model.js

Test = new Meteor.Collection("test");

  if (Test.find().count() < 1) {
    Test.insert({id: 1,
                 name: "test1"});

    Test.insert({id: 2,
                 name: "test2"});
  }

Meteor.publish('test', function () {
  return Test.find();
});

client/test.js

Meteor.subscribe("test");

Test = new Meteor.Collection("test");

Template.hello.test = function () {
  console.log(Test.find().count());//returns 0
  return Test.findOne();
}

Template.hello.events = {
  'click input' : function () {
    // template data, if any, is available in 'this'
    if (typeof console !== 'undefined')
      console.log("You pressed the button");
  }
};

client/test.html

<head>
  <title>test</title>
</head>

<body>
  {{> hello}}
</body>

<template name="hello">
  <h1>Hello World!</h1>
  {{#with test}}
    ID: {{id}}  Name: {{name}}
  {{/with}}
  <input type="button" value="Click" />
</template>

EDIT 1

I want to change the object test, findOne() returns. Let's say for adding an attribute avg which contains the average value of two numbers (test.number1 and test.number2). In my opinion this should look like the following code. But javascript is not synchronous, so this won't work.

Template.hello.test = function () {
  var test = Test.findOne();
  test.avg = (test.number1 + test.number2) / 2;
  return test;
}

EDIT 2

This code worked for me. Now I have to rethink why this solution with 'if (test)' just works with findOne() without a selector in my original project.

Template.hello.test = function () {
  var avg = 0, total = 0, cursor = Test.find(), count = cursor.count();
  cursor.forEach(function(e)
  {
    total += e.number;
  });
  avg = total / count;

  var test = Test.findOne({id: 1});
  if (test) {
    test.avg = avg;
  }

  return test;
}

Upvotes: 0

Views: 2866

Answers (2)

nunobaba
nunobaba

Reputation: 524

The latency the client db uses to replicate data might cause the situation wherein the cursor reckons no results. This especially occurs when the template is immediately rendered as the app loads.

One workaround is to observe query documents as they enter the result set. Hence, something like the following for example happens to work pretty well:

Meteor.subscribe("Coll");

var cursor = Coll.find();

cursor.observe({
  "added": function (doc) {
    ... something...
  }
})

Upvotes: 3

fedosov
fedosov

Reputation: 2049

Try to surround {{#with test}}...{{/with}} with {{#if}}...{{/if}} statement (because in first data push test does not have id and name fields):

<head>
  <title>test</title>
</head>

<body>
  {{> hello}}
</body>

<template name="hello">
  <h1>Hello World!</h1>
  {{#if test}}
    {{#with test}}
      ID: {{id}}  Name: {{name}}
    {{/with}}
  {{/if}}
  <input type="button" value="Click" />
</template>

As a result:

Resulting page

UPDATE:

This code performs calculation of average of field number in all records:

model.js:

Test = new Meteor.Collection("test");

Test.remove({});

if (Test.find().count() < 1) 
{
    Test.insert({id: 1,
                 name: "test1",
                 number: 13});

    Test.insert({id: 2,
                 name: "test2",
                 number: 75});
}

test.js

Test = new Meteor.Collection("test");

Template.hello.test = function () {
  var avg = 0, total = 0, cursor = Test.find(), count = cursor.count();
  cursor.forEach(function(e)
  {
    total += e.number;
  });
  avg = total / count;

  return { "obj": Test.findOne(), "avg": avg };
}

UPDATE 2:

This code snippet works for me:

var test = Test.findOne(); 
if (test) 
{ 
    test.rnd = Math.random(); 
} 
return test; 

Maybe you should try to wrap assignment code into if statement too?

Upvotes: 0

Related Questions