Using connect-assets with Express to precompile Handlebar templates - ember.js

I'm using Express, connect-assets on an Ember project. I'm stuck with making connect-assets to properly precompile the handlebar templates.
I've configured express like this:
app.use(assets({
src: app_root + 'app',
buildDir: './public',
jsCompilers: {
hbs: hbsAssets
}
}));
and with hbsAssets being:
module.exports = {
match: /\.js$/,
compileSync: function(sourcePath, source) {
var match = sourcePath.match(/^.*\/app\/js\/templates\/(.+)\.hbs/)
, templateName = match[1];
var filename = path.basename(sourcePath, '.hbs')
, js = handlebars.precompile(source).toString();
return 'Ember.TEMPLATES' + '["' + templateName + '"] = Handlebars.template(' + js + ');';
}
};
The problem is that the only the hbs layouts get rendered, the {{outlet}}s don't get inserted.
Any help would be appreciated

In the end I ended up using https://npmjs.org/package/ember-template-compiler . It worked out of the box.

Related

Modify how ember-i18n localizations are loaded, split localization strings from main app.js

I am trying to modify the way ember-i18n localizations are loaded. What I want to do is have the localizations in a separate file from the main app javascript file.
Ideally, the structure would remain the same as now. So I would have app/locales/fr/translations.js and app/locales/de/translations.js , each having content similar to this:
export default {
key: "value"
}
So I thought I need to write a custom addon, which would alter the build process. This addon would need to:
Ignore app/locales from final build
Compile all the translation files into one
Transpile the new file with babel
Copy the file in dist/assets/translations.js
The combined translation file would look something like this:
export default {
fr: {
key: "value"
},
de: {
key: "value"
}
This way, I would be able to use and instance initializer and simply import and use this module:
import Translations from 'my-translations';
export function initialize(instance) {
const i18n = instance.lookup('service:i18n');
for(let lang in Translations) {
if(Translations.hasOwnProperty(tag)) {
i18n.addTranslations(tag, Translations[tag]);
}
}
}
Also, index.html would be:
<script src="assets/vendor.js"></script>
<script src="assets/translations.js"></script>
<script src="assets/my-app.js"></script>
Well, I started writing the custom addon, but I got stuck. I managed to ignore the locales, and I wrote code that parses all the localizations, but I do not know how to write the new translations file in dist. What hook do I neeed to use, to be able to write into dist? Any help? Thank you so much.
Here is the code I wrote:
Stuff I use
var Funnel = require('broccoli-funnel');
var stew = require('broccoli-stew');
var fs = require('fs');
var writeFile = require('broccoli-file-creator');
var mergeTrees = require('broccoli-merge-trees');
preprocessTree: function(type, tree) {
if(type !== 'js') {return tree;}
var treeWithoutLocales = new Funnel(tree, {
exclude: ['**/locales/*/translations.js']
});
var translations = {};
var files = fs.readdirSync('app/locales');
files.forEach((tag) => {
if(tag !== 'fr') {return;}
let contents = fs.readFileSync('app/locales/' + tag + '/translations.js', 'utf8');
contents = contents.replace(/^export default /, '');
contents = contents.replace(/;$/, '');
contents = JSON.parse(contents);
translations[tag] = contents;
});
// Should do something with this .. how to write in dist? and when? I need it compiled with babel
var fileTree = writeFile('/my-app/locales/translations.js', 'export default ' + JSON.stringify(translations) + ';');
return treeWithoutLocales;
}
I am not sure if you actually asked a question; but here goes some kind of answer.
Why complicate? Just use James Rosen's i18n addon used by a lot of projects.

Internationalization of ember application

I'm using ember-i18n lib for Internationalisation and want to save current locale in route like:
domain.com - empty for default en
doman.com/es, doman.com/de- for another
For this I tried to use rootURL
Router.reopen({
rootURL: '/' ('es' or 'de')
});
Problem: When rootURL is not empty, app can't redirect and fail with error: ember.debug.js:4903 Uncaught Error: Assertion Failed: Path / does not start with the provided rootURL /es/
Question: What is the best solution to make redirect, all logic will be hold in emebr so I can't move this logic into nginx and etc.
Another option is Make a wrapper route, looks like this:
this.route(
'lang', { path: '/:lang' }, function (){..}
);
This solution looks like not good:
link-to helper will require lang param
lang can't be empty (for default language)
UPDATE: I understand how to dynamic change rootURL, but can't auto redirect.
Found the solution, describe this logic in instance-initializer
export function initialize(app) {
var router = app.lookup('router:main');
var i18n = app.lookup('service:i18n');
var path = window.location.pathname;
var currentLang = ENV.i18n.defaultLocale;
var newPath = '';
var LangFromPath = path.match('^/([a-z]{2})(?:/|$)');
if (LangFromPath && LangFromPath[1]){
currentLang = (ENV.i18n.allowedLocales.indexOf(LangFromPath[1]) > -1) ? LangFromPath[1] : currentLang;
}
if (currentLang != ENV.i18n.defaultLocale) {
var newPath = '/' + currentLang + '/';
}
router.rootURL = newPath;
i18n.set('locale', currentLang);
if (newPath && path.indexOf(newPath) === -1) {
window.location.pathname = newPath;
}
}

How to embed Wufoo form in Ember application

My client has asked me to integrate a Wufoo form into their Ember application, and provided the following JS (anonymized):
<script type="text/javascript">var abc123;(function(d, t) {
var s = d.createElement(t), options = {
'userName':'example',
'formHash':'abc123',
'autoResize':true,
'height':'491',
'async':true,
'host':'wufoo.com',
'header':'show',
'ssl':true};
s.src = ('https:' == d.location.protocol ? 'https://' : 'http://') + 'www.wufoo.com/scripts/embed/form.js';
s.onload = s.onreadystatechange = function() {
var rs = this.readyState; if (rs) if (rs != 'complete') if (rs != 'loaded') return;
try { abc123 = new WufooForm();abc123.initialize(options);abc123.display(); } catch (e) {}};
var scr = d.getElementsByTagName(t)[0], par = scr.parentNode; par.insertBefore(s, scr);
})(document, 'script');</script>
I've tried including it in index.html and also creating a custom component, but keep getting an error from Wufoo:
TypeError: Cannot set property 'innerHTML' of null
Is there a way to use the provided Wufoo JS in an Ember.js app?

How do I return data to a template with Knockout and Requirejs modules?

I'm having a difficult time returning data from a module using RequireJS and Knockout to populate my markup for my single page app. Knockout can't seem to find my data binding observables.
I'm trying to keep each view in a separate js file, but I'm failing to identify where I've gone wrong. Here's what I have so far:
/app/app.js
define(function(require) {
require('simrou');
var $ = require('jQuery'),
ko = require('knockout'),
videoView = require('videoView');
var init = function() {
var viewModel = function() {
var self = this;
self.currentPage = ko.observable();
self.videoView = new videoView();
}
var view = new viewModel();
ko.applyBindings( view );
_router = new Simrou({
'/video/:id': [ view.videoView.getVideo ]
});
_router.start();
};
return {
init: init
};
});
/app/videoView.js
define(function(require) {
"use strict";
var $ = require('jQuery'),
ko = require('knockout');
return function() {
var self = this;
self.currentPage = ko.observable( 'showVideo' );
self.currentVideo = ko.observable();
self.videoData = ko.observableArray([]);
self.videoList = ko.observableArray([]);
var getVideo = function( event, params ) {
// ajax pseudo code
$.ajax({});
self.videoData( dataFromAjaxCall );
}
return {
getVideo: getVideo
};
};
});
index.html
When I browse to /#/video/14 I receive the following error:
Uncaught ReferenceError: Unable to parse bindings.
Bindings value: attr: { 'data-video-id': videoData().id }
Message: videoData is not defined
Here's the markup:
<section id="showVideo" data-bind="fadeVisible: currentPage()=='showVideo', with: $root">
<div class="video" data-bind="attr: { 'data-video-id': videoData().id }></div>
</section>
Like I said, I'm trying to keep each view separated, but I would love some enlightenment on what I'm doing wrong, or if this is even possible? Is there a better more efficient way?
videoData is a property of $root.videoView, not of the root model (the one you passed to applyBindings). It's also an observableArray, so videoData() is just a plain array and even if you get the context right, you won't be able to access its id property, since, being an array, it doesn't have.named properties.

EmberJS not rendering my template

I am using external templates
Ember.TEMPLATES["application"] = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
this.compilerInfo = [2,'>= 1.0.0-rc.3'];
helpers = helpers || Handlebars.helpers; data = data || {};
var stack1, functionType="function", escapeExpression=this.escapeExpression;
if (stack1 = helpers.outlet) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
else { stack1 = depth0.outlet; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
return escapeExpression(stack1);
});
Ember.TEMPLATES["teams"] = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
this.compilerInfo = [2,'>= 1.0.0-rc.3'];
helpers = helpers || Handlebars.helpers; data = data || {};
var buffer = "", stack1, options, helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
buffer += "<div class=\"container-fluid hero team-banner\"><i class=\"icon-cheer\"></i><h1>Fan a Team</h1><span>Choose one or more teams from the list below to get started.</span></div><div class=\"container\"><div class=\"row-fluid team-tab\"><ul class=\"row-fluid nav nav-tabs\"><li class=\"active\"><a>3A</a></li><li><a>2A</a></li><li><a>1A</a></li><li class=\"title\">Conference:</li></ul></div><div class=\"tab-content\"><div class=\"row-fluid tab-pane active\"><div class=\"row-fluid division\"><div class=\"row-fluid division-header\">";
options = {hash:{},data:data};
buffer += escapeExpression(((stack1 = helpers.Team),stack1 ? stack1.call(depth0, depth0.Name, options) : helperMissing.call(depth0, "Team", depth0.Name, options)))
+ "</div><div class=\"row-fluid division-content\"><table class=\"table table-bordered\"><tr><td class=\"team-logo\"><div class=\"img-wrapper\"></div></td><td class=\"name\">Golden St. Elites, Golden Eagles</td><td class=\"location\">San Mateo, CA</td><td class=\"options\"></td></tr><tr><td class=\"team-logo\"><div class=\"img-wrapper\"></div></td><td class=\"name\">Golden St. Elites, Golden Eagles</td><td class=\"location\">San Mateo, CA</td><td class=\"options\"><input /></td></tr><tr><td class=\"team-logo\"><div class=\"img-wrapper\"></div></td><td class=\"name\">Golden St. Elites, Golden Eagles</td><td class=\"location\">San Mateo, CA</td><td class=\"options\"><input /></td></tr><tr><td class=\"team-logo\"><div class=\"img-wrapper\"></div></td><td class=\"name\">Golden St. Elites, Golden Eagles</td><td class=\"location\">San Mateo, CA</td><td class=\"options\"><input /></td></tr></table></div></div></div><div class=\"text-centered\"><a class=\"btn btn-large btn-success\">Start Spinning</a></div></div></div>";
return buffer;
});
which i can confirm are loaded and not throwing errors.
Then I have my application controller and teams controller both of which are loaded and not throwing errors.
App.ApplicationController = Ember.Controller.extend();
App.TeamsController = Ember.Controller.extend
content: []
then I have my views which are loaded and not throwing errors and relate to the templates
App.ApplicationView = Ember.View.extend({
templateName: "application"
});
App.TeamsView = Ember.View.extend({
templateName: "teams"
});
lastly i have a router
App.Router.map ->
this.route('teams', {path: '/'})
I am confused as to how it even knows where to stick the outlet from the external template.
also I don't know if it matters to the router but the page is at '/teams.html' not '/'
if anyone can help, id appreciate it i just need to know how to get this started, right now I am seeing no signs of life.
If the syntax looks off i've been slowly converting some things to coffeescript.
DEBUG: -------------------------------
DEBUG: Ember.VERSION : 1.0.0-rc.1
DEBUG: Handlebars.VERSION : 1.0.0-rc.3
DEBUG: jQuery.VERSION : 1.9.1
DEBUG: -------------------------------