Meteor.publish/Subscribe issue - javascript

I need to display data to all clients using Meteor.publish/subscribe.I did one sample example in that example what i am did is 10 records are inserted at that time of server startup and these 10 records are trying to display to all clients.The Problem is The data doesn't shows the clients.I didn't have any idea because i am new to meteor JS.So Please see the below code and suggest me how to do?
HTML Code :
<head>
<title>DataApp</title>
</head>
<body>
{{> main}}
</body>
<template name="main">
{{#each messages}}
{{messages}}
{{/each}}
</template>
ANd JS Code is :
Messages = new Meteor.Collection("messages");
if (Meteor.isClient)
{
Meteor.subscribe('messages');
}
if (Meteor.isServer)
{
Meteor.startup(function ()
{
// code to run on server at startup
for(var i = 0 ; i <= 10 ; i++ )
{
console.log("EXE"+i);
Messages.insert({ name: "EXE"+i });
}
});
Meteor.publish('messages', function() {
return Messages.find();
});
}

Firstly, you are missing a template helper on your template main, so make your Meteor.isClient look like this:
if (Meteor.isClient) {
Meteor.subscribe('messages');
// this is the template helper that is referenced by {{messages}}
// in your template 'main'
Template.main.messages = function () {
return Messages.find();
};
}
Secondly, the handlebars in your html don't make sense, try this instead:
<template name="main">
<!-- inserts value of property 'name' of each object in 'messages' -->
{{#each messages}}
{{name}}
{{/each}}
</template>

Related

Returns Data Issue in Meteor?

I need to know about the below shown Issue :
JS Code:
Template.main.helpers({
ItemName: function() {
var self = this;
console.log("helpers : " +self.fieldoptions);
return _.map(self.fieldoptions,function(p)
{
p.parent = self;
return p;
});
}
});
HTML Code :
{{#each ItemName}}
{{this.parent.fname}}
{{/each}}
The above Js return code doesn't show the html.So how to show the above return code in HTML.I didn't get any idea about this.So please help me?
Its not clear to me so I'll write what I think is happening. You should have at least 2 files on your meteor directory (the one created with meteor create)
template.main.html that if you are not using any router to make the template append to the body should look like
<head>
<title>My title</title>
</head>
<body>
{{> templateMain}}
</body>
<template name="templateMain">
{{#each ItemName}}
{{fname}}
{{/each}}
</template>
template.main.js with something around these lines
FieldNames = new Meteor.Collection('fieldname');
if( Meteor.isServer && FieldNames.find().count() === 0)
_.each(['one','two','three','four'], function(value, index){
FieldNames.insert({ fname : value, index : index });
});
if(Meteor.isClient){
Template.main.helpers({
ItemName: function() {
return FieldNames.find();
}
});
}
So what I think was happening was that you didn't include the template on the body.
Let me know if something is not clear.

Meteor Collection RefrenceError

I'm running Meteor 0.8.0
I'm getting a ReferenceError from the browser console when attempting to insert to a Meteor Collection. FYI, I've removed the autopublish package for this app in order to play with publications and subscriptions.
Template
<head>
<title>itemsApp</title>
</head>
<body>
{{> name}}
{{> items}}
</body>
<template name="name">
<input type="text" />
</template>
<template name="items">
<h1>Items</h1>
<ul>
{{#each items}}
<li>{{name}} | {{category}}</li>
{{/each}}
</ul>
</template>
Code
var Items = new Meteor.Collection("items");
if (Meteor.isClient) {
Meteor.subscribe("items");
Template.items.items = function () {
return Items.find();
};
}
if (Meteor.isServer) {
Meteor.publish("items", function () {
return Items.find();
});
}
Now, from the browser console (FF28 & Chromium 33.0.1750.152 on Ubuntu 13.10), I'm getting
ReferenceError: Items is not defined
when I run:
Items.insert({name: "iPod", category : "Apple"});
Any ideas?
Thanks!
In Meteor, variables defined with var keywords are local to the file they're in. So in your case
var Items = new Meteor.Collection("items");
is local. Simply remove the keyword:
Items = new Meteor.Collection("items");
Now Items is a global variable and can be accessed in other files (and from console).

meteor: render a template in a specific context

I have two templates
<body>
{{>tmpl1}}
{{>tmpl2}}
....
</body>
in the tmpl1 I have a list of items, which can be clicked. When one is click, tmpl2 shown the details. How can this be achieved ?
So, just to make the idea clearer, here is how I get the list of items
Template.tmpl1.items = function () {
return Items.find({}).fetch();
};
tmpl1 displays them as follows
<template name="tmpl1">
{{#each items}}
{{title}}
{{/each}}
....
</template>
So tmpl2 template might look like this
<template name="tmpl1">
<h1>{{title}}</h1>
<p>{{content}}</p>
</template>
Any suggestions how to link the selected item in tmpl1 with tmpl2 ?
First, put your templates in a container so that you can manipulate the context. Also, put the details template in a #with context:
<template name="box">
{{> list}}
{{#with item}}
{{> details}}
{{/with}}
</template>
Now, add the event handlers for the box template. Assuming your entries in the list looks like this:
<div class="listItem" data-id="{{_id}}">{{title}}</div>
Write the handler:
Template.box.events({
'click .listItem': function(e, t) {
t.data.itemId = $(e.target).data('id');
t.data.itemDep.changed();
}
});
Finally, create the data helper and dependency for the selected item:
Template.box.created = function() {
this.data.itemDep = new Deps.Dependency();
};
Template.box.item = function() {
this.itemDep.depend();
return Items.findOne(this.itemId);
};

Helpers in templates

Seeing if I can insert a helper into a template. Seems like I'm doing something wrong because you can't actually click the buttons in my program.
HTML:
<head>
<title>BubblePopper</title>
</head>
<body>
{{loginButtons}}
{{>home}}
</body>
<template name ="grid">
<div id="container">
{{#each buttons}}
<button class="button" type="button"></button>
{{/each}}
</div>
</template>
<template name = "home">
<h1> Welcome to bubblePopper</h1>
<p> Current Game Status:
//this is the part I'm confused about is it ok to insert the grid helper into this
//if statement in the template?
{{#if game.active}}
Game in progress. Finish Game<br>
<center>{{>grid}}</center>
{{else}}
{{#if game.finished}}
Game done or another player left.Start a new game
{{else}}
Waiting for a new player to login. Find a new game
{{/if}}
{{/if}}
</p>
<p><strong> Current Game ID: </strong>{{game._id}}</p>
<p><strong> Current Game Player Count: </strong>{{game.players.length}}</p>
<p><strong> Current Game Active: </strong>{{game.active}}</p>
</template>
Client.JS:
if (Meteor.isClient) {
Deps.autorun(function(){
gameSubscription = Meteor.subscribe("myGames",Meteor.userId());
});
Template.home.game = function(){
return gameCollection.findOne({current: true});
};
Template.home.events({
"click #newGame" : function() {
Meteor.call('newGame')
},
"click #finishGame": function(){
var game = gameCollection.findOne({current: true});
Meteor.call('finishGame', game._id);
}
});
//was confused if I should just include buttons as a part of homes template
Template.grid.buttons = function (){
var list = [];
for(var i=1; i<=64; i++){
list.push({value: i});
}
return list;
}
Template.button.events({
'click .button': function(ev) {
$(ev.target).css('visibility', 'hidden');
console.log("pop")
}
});
}
I didn't include the server.js because it has nothing to do with any of the template helper relationship. Is this the right way to insert the grid? Also is it an error in my HTML that isn't allowing the buttons to be clicked?
Looks like you've mixed up the name of your template. If it's the buttons in the grid template you're referring to, you need to change the line Template.button.events({ to Template.grid.events({ and then you should see the function being executed when a button is clicked.

Dynamically loading templates in Meteor.js

I would like the ability to load templates dynamically without explicitly specifying the template.
As an example:
<template name="foo">
</template>
where 'foo' is the template, I would like the ability to load it dynamically by calling some method:
Meteor.render(Meteor.loadTemplate('foo'));
Is this possible?
Here's how to dynamically render templates, as of Meteor 0.9.4 - 1.0. All other answers were obsolete at the time of this writing.
Let's say you're editing a bunch of records, or creating a new one, and want to render either the update template, or the new template, based on some Session variables.
There are two ways to do this:
1) This is the officially recommended method for Meteor 0.9.4 or newer - it uses Template.dynamic:
<template name="records">
{{> Template.dynamic template=whichOne}}
</template>
<template name="recordUpdate">
...
</template>
<template name="recordNew">
...
</template>
Template.records.helpers({
whichOne: function () {
return Session.get('edit') ? 'recordUpdate' : 'recordNew'
// note that we return a string - per http://docs.meteor.com/#template_dynamic
}
});
2) This works in various Meteor versions, but isn't recommended officially because it's unclear that the template is chosen dynamically:
<template name="records">
{{> whichOne}}
</template>
{{! Note how "whichOne" is indistinguishable from a constant template name... }}
{{ ...like "recordUpdate" or "recordNew" below. }}
<template name="recordUpdate">
...
</template>
<template name="recordNew">
...
</template>
Template.records.helpers({
whichOne: function () {
return Session.get('edit') ? Template.recordUpdate : Template.recordNew
// note that we return a Template object, not a string
}
});
To pass a data context to the template, use:
{{> Template.dynamic template=whichOne data=myData}}
Meteor 0.9.x New API
Dan Dascalescu pointed out Meteor now has built-in dynamic templates! This is nice because you do not need to include the extra code as seen in previous versions.
{{> Template.dynamic template=template [data=data] }}
For Meteor 0.8.x Legacy
Dynamic Template Without Data: Boris Kotov's updated Blaze (0.8.0) answer is on the right track (taken from the latest docs), but it doesn't work as-is for me. I got the following to work:
{{> dynamicTemplate name=myDynName}}
<template name="dynamicTemplate">
{{#with chooseTemplate name}}
{{> template}}
{{/with}}
</template>
Template.dynamicTemplate.chooseTemplate = function (name) {
return { template: Template[name] };
};
I hope there is a simpler solution, but I needed to wrap the Template in a JSON as shown. Maybe this will help someone else to move forward.
Dynamic Template With Data: If you have and want data to be dynamic, be sure to make a helper method that can react. Be sure to do a Session.set() somewhere to see the effect.
// Inside "myContainingTemplate"
{{> dynamicTemplateWithData name=myDynName data=myDataHelper}}
<template name="dynamicTemplateWithData">
{{#with chooseTemplate name}}
{{#with ../data}}
{{> ..}}
{{/with}}
{{/with}}
</template>
Template.dynamicTemplateWithData.chooseTemplate = function (name) {
return Template[name];
};
Template.myContainingTemplate.helpers({
myDataHelper: function () {
Session.get('myReactiveKey');
}
});
You have found Meteor.render but what you are missing is the template loading.
In the docs it mentions that you can call Template.foo() to return the HTML for a template.
http://docs.meteor.com/#template_call
Putting that together you access the template foo or any other using bracket access so:
var templateName = "foo";
var fragment = Meteor.render( function() {
return Template[ templateName ](); // this calls the template and returns the HTML.
});
Then fragment is your Reactive fragment, so that your template can continue to receive live updates. Your fragment now needs placing in the web page (I use jQuery, so this example does as well):
$("#htmlnode").html( fragment );
$("#htmlnode") is just a node in your DOM where you want the template rendered. And you now have the rendered content in your web page.
I'm just doing it like this, no jQuery required:
EDITED
Template.mainContent.showContentFromRouter = function() {
return Template[Meteor.Router.page()]();
};
In this case I'm using the Meteor Router, and return whatever template that I choose to (from the Router), but you could just do this:
Template.mainContent.showDynamicContent = function() {
return Template['someTemplateYouveDefined']();
};
Update for blaze:
https://github.com/meteor/meteor/wiki/Using-Blaze#templatefoo-is-not-a-function-and-does-not-return-a-string
Dynamically render a template with a given data context
Old:
{{dynamicTemplate name="templateName" data=dataContext}}
Template.foo.dynamicTemplate = function (opts) {
return Template[opts.name](opts.data);
};
New: (Notably, in Blaze, keyword arguments to inclusion or block helpers are bundled into a single object which becomes the new data context)
{{> dynamicTemplate name="templateName" data=dataContext}}
<template name="dynamicTemplate">
{{#with chooseTemplate name}}
{{#with ../data}} {{! original 'data' argument to DynamicTemplate}}
{{> ..}} {{! return value from chooseTemplate(name) }}
{{/with}}
{{/with}}
</template>
Template.dynamicTemplate.chooseTemplate = function (name) {
return Template[name];
}
By the way, I don't really played with it, but this is what I took from the new blaze docs. So I think it should be the way to do it ;)
From https://github.com/meteor/meteor/wiki/Using-Blaze
{{> post}}
Template.foo.helpers({
post: function () {
return Template[this.postName];
}
});
Template inclusions now search the namespace of helpers and data for template objects, so it's easy to programmatically choose which template to use. This is a powerful feature, and will allow patterns like assigning one template as a helper of another so that it can be overridden.
Meteor 0.8.x Legacy
Using Joc's answer as a guide,
I've achieved similar using http://docs.meteor.com/#template_call, but using a helper instead, as suggested by the docs:
When called inside a template helper, the body of Meteor.render, or other settings where reactive HTML is being generated, the resulting HTML is annotated so that it renders as reactive DOM elements
My client.js looks a bit like this:
Template.myPageTemplate.helpers({
dynamicTemplate: function() {
// conditional logic can be added here to determine which template to render
return Template.myDynamicTemplate();
}
});
and my html looks like this:
<template name="myPageTemplate">
<h1>My Template</h1>
{{{dynamicTemplate}}}
</template>
<template name="myDynamicTemplate">
<h1>My Dynamic Template</h1>
</template>
Based on hillmark's answer, this is the easiest it could get:
Template.main.template = function() {
if (some_condition) {
return Template.A();
} else {
return Template.B();
}
};
With the corresponding .html
<body>
{{> main}}
</body>
<template name="main">
{{{template}}}
</template>
<template name="A">
<h1>Template A</h1>
</template>
<template name="B">
<h1>Template B</h1>
</template>
Edit
Doesn't work in Meteor 0.8.0
for me the easiest way was to just create a function get_dynamic_template, so something like:
var a= get_dynamic_template(template_name,data);
which returns what can be rendered as a normal variable {{a}}
The code for this function is quite simple:
var get_dynamic_template = function(template_name,data)
{
return function(){
return new Handlebars.SafeString(
UI.toHTML(
Template[template_name].extend({data: function () { return data; }}))
);
};
}
This would handl dynamic templates both with and without data:
(requires Blaze/ Meteor 0.8)
{{> dynamicTemplate name=templateName}}
<template name="dynamicTemplate">
{{#with chooseTemplate name }}
{{#if ../data}}
{{#with ../data }}
{{> .. }}
{{/with}}
{{else}}
{{> this}}
{{/if}}
{{/with}}
<template name="dynamicTemplate">
template javascript:
Template.dynamicTemplate.chooseTemplate = function (name) {
return Template[name];
};

Categories