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
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.
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;
}
}
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?
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.
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: -------------------------------