Standalone Blaze/Tracker


#1

Hi Guys,

Not sure if anyone has done this for a while ( I certainly couldn’t find anything ).

I’m balls deep in Blaze right now so when doing a project outside of Meteor I thought it would be nice to be able to preserve the nice reactive/declarative data binding/templating Blaze gives you. However, it seems MDG currently have a standalone on their to-do list but haven’t looked at it for a while.

Also, due to the popularity of of frameworks like React etc right now there doesn’t seem to be much demand for this sort of thing - so I had to do it myself.

Was a bit of a pain having to rip the necessary packages and their dependencies out of a bundled Meteor app (1.2.1) and there’ll be a bit of redundant rubbish in there right now as I haven’t cleaned it up a great deal yet, but it all works at least :slight_smile:

Here’s a gist with the file in (minified and unminified for those that want to clean it up a bit). https://gist.github.com/calvin-evans/0bb115030c7785087002

Just include in your page and you’re good to go - you’ll just need to define your templates, could do this by traversing the DOM and looking for <template> tags or something.

In my app I’m rendering as much as I can server-side with handlebars then injecting Blaze templates in the client. I’m far from an elegant solution, but if anyone is interested I’m currently doing the following… use at your own risk :slight_smile:

<script>
            var renderFuncCode; 
            var name;

            {{#templates}}
                renderFuncCode = SpacebarsCompiler.compile($($.parseHTML("{{template}}")).text(), {isTemplate: true});
                name = "{{{name}}}";
                {{#if (devEnv)}}console.log("Adding Template: " + name);{{/if}}
                // TODO: remove eval()
                eval("Template.__define__(" + JSON.stringify(name) + ", " + renderFuncCode + ");");
            {{/templates}}

            Blaze.Var = ReactiveVar;
</script>

#2

@webantic Could you give example code of this being used on a simple page? Maybe just a simple counter so that you can show tracker as well?


#4

@larry sure, I’ve changed it a little bit as well. The way I register templates is now like this:

{{#if templates}}
    {{!-- blaze --}}
    <script src="/js/vendor/blaze.min.js"></script>

    {{!-- define Blaze templates --}}    
    {{#templates}}
		<template name="{{{name}}}">{{{template}}}</template>
    {{/templates}}
		<script>
			var compileTemplate = function(name, html_text) {
			  try {
			    var compiled = SpacebarsCompiler.compile(html_text, { isTemplate:true }),
			    		renderer = eval(compiled);
		      // Template[name] = new Template(name,renderer);
		      Template.__define__(name, renderer);
			  } catch (err){
			    console.log('Error compiling template:' + html_text);
			    console.error(err);
			  }
			};		
			$("template").each(function(i,e){
				compileTemplate($(e).attr("name"), e.innerHTML.replace("&gt;", ">"));
				$(e).remove();
			});
		</script>
{{/if}}

I then render one of two ways. In the admin area I use client-side routing with page.js which looks a bit like this:

page.base("/admin");

/**
 * Route Definition
 */

page('/dashboard', function(ctx){
	render("admin_dashboard", "Admin | Dashboard", ctx);
});

You’d then have your event maps, helpers etc as you would in Meteor. For example. a very basic cart might look something like this

Orion.cart = {
	dep: new Tracker.Dependency(),
	items: JSON.parse(localStorage.getItem("cartItems")) || [],
	add: function(item){
		Orion.cart.items.push(item);
		localStorage.setItem("cartItems", JSON.stringify(Orion.cart.items));
		Orion.cart.dep.changed();
	}
};

Template.cart.onCreated(function(){
	var self= this;
	self.total = new ReactiveVar(Orion.cart.items.length);
	self.autorun(function(){
		Orion.cart.dep.depend();
		self.total.set(Orion.cart.items.length);
	});
});

Template.cart.helpers({
	cartTotal: function(){
		return Template.instance().total.get();
	}
});

On non-admin pages, rendering is done by the server but I use a data-bind attribute to replace portions of the HTML with a Blaze template. e.g:

jQuery(document).ready(function($){
    $("[data-bind]").each(function(i,e){
        e.innerHTML= null;
        Blaze.render( Template[$(e).attr("data-bind")], e );
    });
});

So you could have something like:

<div data-bind="cart">
   <p>1 items</p>
</div>

And it would get turned into a Blaze view once the dom had rendered.