How to dynamically create a Blaze Template from database string - meteor

I'm using Meteor's blaze viewmodel.org, a couple of years back I found a way to save blaze templates and viewmodels in database and render them dynamically, But unforuntatley I lost the code and I could not recreate this as it was not documented anywhere.
How do I recreate the same behavior?
Sample database
db.templates.insert({
name: "templateName",
blaze: "Hello {{viewmodelNameHelper}}",
viewmodel: " { onCreated() {console.log('oncreated hook')}, viewmodelNameHelper(){return 'Your Name!'} }"
});
viewContainer.html
<template name="viewContainer">
{{ myRenderTemplateHelper }}
</template>
viewContainer.js
Template.viewContainer.viewmodel({
onCreated(){
// subscribe for template from database
},
myRenderTemplateHelper(){
// required code here
}
})
Output
Hello Your Name!
Please note that Template.dynamic and Blaze.renderWithData() won't help as I need to attach the dynamic viewmodel object to the created template instance. where all the viewmodel helpers and events are reactive.
I also tried to do the same using react but I couldn't find enough resources on that?

Related

Meteor not displaying data from collection in html

I am trying to get data from a collection in meteor and using a helper passing it to a template.
Here is my code in collection:
Meteor.publish('displayCustomers', function tasksPublication() {
return Customers.find();
});
Below code in template JS file
Template.customerlist.onCreated(function() {
Meteor.subscribe('displayCustomers');
});
Template.customerlist.helpers({
displayCustomers :function(){
console.log(Customers.find({}));
return Customers.find({});
},
});
Template:
<template name="customerlist">
<h1>All registered users</h1>
{{#each displayCustomers}}
{{fname}}
{{/each}}
</template>
It is only displaying HTML content i.e. <h1>All registered users</h1>
Check that your publication is returning values to the client with this MiniMongo chrome extension
Check to make sure Customers is defined on the server and that your publish block is running only on the server.
Also I would toss a debugger into your onCreated block to make sure that your subscribe is being initialized.
Other than that, your code looks fine. I would try installing MeteorToys Mongol for client pub/sub debugging. https://atmospherejs.com/msavin/mongol
You need to actually fetch documents in your template :
Template.customerlist.helpers({
displayCustomers :function(){
return Customers.find().fetch(); //will return an array with all published documents
},
});

Create/modify Meteor templates at runtime

I am wondering how to solve this problem:
I have a template which contains some text with some template helpers inside:
<template>Hello {{who}}, the wheather is {{weather}}</template>
Now I need to change the content of the template dynamically at runtime, while maintaining the helper functionality. For example I would need it like this:
<template>Oh, the {{weather}}. Good evening {{who}}</template>
The text changes and the helpers are needed at different positions. Think of an application where users can create custom forms with placeholders for certain variables like the name of the user who fills out the form. Basically, the content of the template is stored in a mongo document and needs to be turned into a template at runtime, or an existing template needs to be changed.
How to approach this? Can I change the contents of a template at runtime?
To solve this use case you need to use two techniques.
Firstly you need to be able to change the template reactivel. To do this you can use Template.dynamic. eg:
{{> Template.dynamic template=helperToReturnName [data=data] }}
See here: http://docs.meteor.com/#/full/template_dynamic
Now that you can change template, you need to be able to create new templates on the fly from you database content. This is non trivial, but it's possible if you're willing to write code to create them, like this:
Template.__define__("postList", (function() {
var view = this;
return [
HTML.Raw("<h1>Post List</h1>\n "),
HTML.UL("\n ", Blaze.Each(function() {
return Spacebars.call(view.lookup("posts"));
},
function() {
return [ "\n ", HTML.LI(Blaze.View(function() {
return Spacebars.mustache(view.lookup("title"));
})), "\n " ];
}), "\n ")
];
}));
That code snippet was taken from this article on Meteorhacks, and the article itself goes into far more detail. After reading the article you'll be armed with the knowledge you need to complete the task...
Just have a helper dynamically build the entire string (remembering that this refers to the current data context):
Template.foo.helpers({
dynamicString: function(switch){
if ( switch == 1) return "Hello "+this.who+", the wheather is "+this.weather;
else return "Oh, the "+this.weather+". Good evening "+this.who;
}
});
Then in your template:
<template name="foo">
{{dynamicString}}
</template>
Alternatively, just use {{#if variable}} or {{#unless variable}} blocks to change the logic in your template. Much, much simpler.
<template name="foo">
{{#if case1}}
Hello {{who}}, the wheather is {{weather}}
{{else}}
Oh, the {{weather}}. Good evening {{who}}
{{/if}}
</template>
You can always have a template helper that computes the necessary boolean variables (e.g. case1).

Meteor JS and State (address) select element

I want to have a state select in meteorjs for an address input field. I feel like listing out all the states in a massive html string of <option>s is wrong. Is there a documentation or preferred way to do this?
In frameworks like CakePHP, I would create a DB table related to address and just use the form helper methods to output the markup based on the table.
If you'd prefer to fetch a set of states from a database, you could create a Meteor Collection to store them.
States = new Mongo.Collection("states");
If you've removed the autopublish package (which if you haven't, you should), you need to then publish this collection,
if (Meteor.isServer) {
Meteor.publish("states", function() {
return States.find();
}
}
and then subscribe to it, and make it available to your template with a helper:
if (Meteor.isClient) {
Meteor.subscribe("states");
Template.myForm.helpers({
states: function() {
return States.find();
}
});
}
Then you can output the collection in your template as such:
<select>
{{#each states}}
<option>{{name}}</option>
{{/each}}
</select>
A nice way to enter the data into the database is through the Meteor Mongo shell or through a GUI like RoboMongo

Turning a plain JS Object into a reactive one

I am working on an edit form that has two paths. One is when the user clicks a "New" button, the other is when they click "Edit".
When they click "New", the code sets a form_id Session var to null and a client_id session variable to null, then does a Router.go('formEdit') to load the formEdit template/route.
In the formEdit.js, I do a reactive Template helper (I think that's what they are called, but anyway) like so:
Template.formEdit.form = function() {
var form;
if (Session.equals('form_id', null)) {
// Create empty form
form = {
title: null,
client_id: Session.get('client_id'),
header_fields: [],
form_fields: []
};
} else {
// Load form
form = Forms.findOne({_id: Session.get('form_id')});
}
return form;
}
Basically I check if the form_id was set or not, if so I load it from the Forms collection, if not I create a blank one. I thought this would be pretty simple, really.
The problem is that the created/found form object does not behave in a "reactive" way. If I add header_fields or form_fields the subsequent template code never updates. Both are in a {{#each}} like so:
<template name="formEdit">
...
{{#each header_fields}}
{{> headerFieldOutput}}
{{/each}}
...
{{#each form_fields}}
{{> formFieldOutput}}
{{/each}}
</template>
How do I make it such that I can push header_fields and form_fields onto the form and have the underlying template reactively update the {{#each}}'s?
I think you're going about it a little differently than what the reactive programming methodology in Meteor is expecting.
You're putting the 'display' logic in your template helper, rather than using the template scaffolding itself to do it.
So, declare a very simple template helper, something like this:
Template.formEdit.form = function () {
return forms.findOne(Session.get("form_id"));
};
And then, in your template scaffolding have something like this:
{{#if form}}
{{#with form}}
{{#each header_fields}}
etc...
{{/with}}
{{#else}}
[[insert your blank form scaffolding in here]]...
{{/if}}
Then, as you set your Session form_id variable, you can set it to null to invoke the {{#else}} portion.
There are more details than this (logic in the form submit click handler to identify if you are performing an update or an insert, for example) but hopefully you get the gist of it from this.
You should try to gain a better understanding about how cursors and reactive computations work, as it will help you better understand how to best use the reactive methodology. A good starting place is the parties example (watch the video and walk through the code manually). It's similar to what you're doing, and shows a good way of building your templates for when you don't have a 'selected' object.
Hope this helps!

Meteor reusable components

Meteor's reusable UI components is still far away on the roadmap. What's the best community approved way to create reusable components? A system based on Session seems so global.
Let's say I want to create 2 different chat channels on 1 page at the time. What do I do?
Presuming you're doing chat through collections...
I would make it such that a certain value is added to the chat JSON going into the MongoDB. Say for instance, user test sends a message hello world in chat box 1. The JSON I'd send would look something like
{name: 'test', message: 'hello world', num: 1}
Then, in my chat helper thing, wherever I'm displaying new chats, I'd use a get method like this
UI.registerHelper(getChat, function(n){return Messages.find({num: n});})
Which would be called in the HTML with
{{#each getChat 1}} or {{#each getChat 2}} or whatever, depending on how many chat boxes you have.
This would basically only return values that correspond to the specific chat box.
Good luck.
If you want to use something dynamic instead of fixed param value, you can try this
// In memory collection for demonstration purpose
Messages = new Meteor.Collection(null);
if (Messages.find().count() === 0) {
Messages.insert({name: 'test2', num: 1});
Messages.insert({name: 'test5', num: 2});
// [...] Init some test data
}
Template.test.helpers({
// you can also use a collection
chats: function() { return [{num:1}, {num:2}] },
});
// Took from Bob's example
UI.registerHelper('getChat', function(n){
return Messages.find({num: n});
});
And your template
<template name="test">
{{#each chats}}
{{! num refer to a property of 'this'}}
{{#each getChat num}}
{{name}} <BR />
{{/each}}
{{/each}}
</template>
You can read more about Custom Block Helpers in Blaze here

Resources