Unable to use partials in handlebars Email templates - handlebars.js

I am trying to use partials inside email templates. I am using 'express-handlebars' as templating engine at the app level
exphbs = require('express-handlebars')
var viewsPath = path.join(__dirname, '/app/views');
app.set('views', viewsPath);
var hbs = exphbs.create({
defaultLayout: 'main',
layoutsDir: viewsPath + '/layouts',
partialsDir: viewsPath + '/partials'
});
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');
And I have a helper for sending emails as below:
var templateDir = path.join(__dirname, '../views/email_templates');
var EmailTemplate = require('email-templates').EmailTemplate;
function sendEmail(options,done){
var template = new EmailTemplate(templateDir + "/" + options.template);
template.render(options, function(err, result){
var message = {
'to' : [options.toEmail],
'from_email' : 'support#xyz.com',
'from_name' : 'XYZ',
'headers' : {
"Reply-To" : 'support#xyz.com'
},
'subject' : options.subject,
'html' : result.html
};
var to_address = message.to[0].email;
ses_client.sendEmail({
'from' : message.from_email,
'replyTo' : message.from_email,
'subject' : message.subject,
'to' : to_address,
'message' : message.html
},function (err, data,res){
if(err) logger.log('error', 'Error in sending email' + err);
return done();
});
});
}
When I include a partial in my html.handlebars template as {{> myPartial}}, I get the following error: The partial myPartial could not be found
I have verified that the partial file is at the same path as specified above at
"partialsDir: viewsPath + '/partials'"
How can I get my partials to be rendered inside the email templates?
I have tried using https://stackoverflow.com/a/12700409/6165688 but still I get the same error of partial not being found.

Finally got the partials working for my E-mail templates. I referred to this link and switched to nodemailer npm from the email-templates that I was using earlier.

Related

Can't able to fetch the user location in meteor

I developed a meteor app in which while registering I am fetching the user location at the client side, to do so I have added the packages listed below:
meteor add mdg:geolocation
meteor add jeremy:geocomplete
meteor aldeed:geocoder
meteor add jaymc:google-reverse-geocode
The code written at client side is as follows:
if (Meteor.isClient) {
Meteor.startup(() => {
GoogleMaps.load({
v: '3.26',
key: '',
libraries: 'geometry,places'
});
console.log("is GoogleMaps.loaded",GooglMaps.loaded());
});
Template.Registration.onRendered(function () {
Tracker.autorun(() => {
if (GoogleMaps.loaded()) {
$('#txt_address').geocomplete({country: "AU", type:
['()']});
}
});
var date = new Date();
$('#div_dob').datetimepicker({
format: 'DD/MM/YYYY',
maxDate : date,
ignoreReadonly: true
});
date=null;
});
Template.Registration.helpers({
location:function(){
$('input[name="txt_address"]').val(Session.get('location'));
}
});
Template.Registration.events({
'click #btn_findlocation':function(event){
alert('Find Location')
event.preventDefault();
function success(position) {
var crd = position.coords;
console.log(`Latitude0 : ${crd.latitude}`);
console.log(`Longitude0: ${crd.longitude}`);
var lat = crd.latitude;
var long = crd.longitude;
reverseGeocode.getLocation(lat, long, function(location)
{
console.log("Address",JSON.stringify(reverseGeocode.getAddrStr()));
Session.set('location', reverseGeocode.getAddrStr());
});
};// end of function success(position)
function error(err) {
console.warn('ERROR(' + err.code + '): ' + err.message);
};//end of function error(err)
// geolocation options
var options = {
enableHighAccuracy: true,
maximumAge: 0
};// end of var options
navigator.geolocation.getCurrentPosition(success, error,
options);
},
})
}
But I am getting false value for GoogleMaps.loaded() function and the following below error when I click a button to fetch the location.
Can't able to read formatted address of undefined.
Results are inconsistent as sometimes I was able to fetch the location other times not.
Please give any suggestions...

How do you update a Set on DynamoDB using JavaScript document client?

I'm trying to add some items to a DynamoDB set. This worked fine with the original JavaScript SDK, but not with the new DocumentClient, using the createSet() function. Here's my code:
'use strict';
let docClient = new AWS.DynamoDB.DocumentClient({
region: 'us-east-2',
accessKeyId: 'AKIAJWIR35J4YZF4RQVQ',
secretAccessKey: 'xxxx'
});
var params = {
TableName : 'qa_Web_Application',
Key: {'Application_ID': '78f27a00-11f6-49cc-9adb-ae0795cf79d4'},
UpdateExpression : 'ADD #idList :newIds',
ExpressionAttributeNames : {
'#idList' : 'ids'
},
ExpressionAttributeValues : {
':newIds' : docClient.createSet([1,2])
}
};
console.log( params.ExpressionAttributeValues[":newIds"] );
docClient.update(params, function(err,data) {
if( err !== null ) {
console.log( err, err.stack );
} else {
console.log ( data );
}
});
Here's the output:
constructor {values: Array(2), type: "Number"}
Error: Invalid UpdateExpression: Incorrect operand type for operator or function; operator: ADD, operand type: MAP
I've seen this same question here (How do you update a Set on DynamoDB using JavaScript document client?), but that's what I'm basing this code example on, and it fails.

http into a service with Angular2 with es5

I am working with Angular2 and es5. I want to use http in a service.
Unfortunately I have 2 errors:
- http is undefined, but ng.http.Http is defined,
- I have this error for the main component:
vendor-client.min.js:28 EXCEPTION: Can't resolve all parameters for class0: (t, ?)
Here is my service code:
;(function(app, ng) {
console.log(new ng.http.Http());
app.ApplicationsService = ng.core.Injectable().Class({
constructor: [ng.http.Http, function(http) {
console.log(http);
this.applicationsEmailUrl = 'api/applications/email';
this.http = http;
}],
emailExists: function(email) {
console.log(email);
var data = { email: email };
return this.http.post(this.applicationsEmailUrl, data)
.toPromise()
.then(function(response) { response.json().data; })
.catch(this.handleError);
}
});
})(window.app || (window.app = {}), window.ng);
Here is the main component:
;(function(app, ng) {
app.AppComponent = ng.core
.Component({
selector: 'register-form',
templateUrl: 'src/register/app.component.html'
})
.Class({
constructor: [ng.core.ElementRef, app.ApplicationsService, function(ref, Applications) {
console.log('app.component.js');
this.programs = JSON.parse(ref.nativeElement.getAttribute('programs'));
this.applications = Applications;
}],
emailExists: function(email) {
console.log('emailExists() triggered');
Applications.emailExists(email);
}
});
})(window.app || (window.app = {}), window.ng);
The bootstrap:
;(function(app, ng) {
document.addEventListener('DOMContentLoaded', function() {
ng.platformBrowserDynamic.bootstrap(app.AppComponent, [
ng.forms.disableDeprecatedForms(),
ng.forms.provideForms(),
ng.http.HTTP_PROVIDERS,
app.ApplicationsService
]);
});
})(window.app || (window.app = {}), window.ng);
If I try to inject http into the main component within the providers array, it works. But I would rather prefer to have a service.
I found out the problem. Looks like Angular2 needs to load your code in order. The main component was loaded before the service, so it was undefined. I put all my code in one file and it works. I will use a require loader asap.

How to properly build an AMD app as a single file with r.js using grunt?

I keep seeing this error when executing the compiled file:
Uncaught Error: No json
Here's my current requirejs grunt task configuration:
requirejs: {
options: {
baseUrl: "build/repos/staging/dev",
mainConfigFile: "dev/main.js",
generateSourceMaps: false,
preserveLicenseComments: false,
name: "almond",
out: "./static/js/compiled.js",
//excludeShallow: ['vendor'],
findNestedDependencies: true,
removeCombined: true,
//wrap: true,
optimize: "uglify2",
uglify2: {
output: {
beautify: true,
},
lint: true,
mangle: false,
compress: false,
compress: {
sequences: false
}
}
}
}
And here's my dev/main.js file:
// This is the runtime configuration file.
// It also complements the Gruntfile.js by supplementing shared properties.require.config({
waitSeconds: 180,
urlArgs: 'bust=' + (new Date()).getTime(),
paths: {
"underscore": "../vendor/underscore/underscore",
"backbone": "../vendor/backbone/backbone",
"layoutmanager": "../vendor/layoutmanager/backbone.layoutmanager",
"lodash": "../vendor/lodash/lodash",
"ldsh": "../vendor/lodash-template-loader/loader",
"text": "../vendor/requirejs-plugins/lib/text",
"json": "../vendor/requirejs-plugins/json",
"almond": "../vendor/almond/almond",
// jquery
"jquery": "../vendor/jquery/jquery",
"jquery.transit": "../vendor/jquery.transit/jquery.transit",
"jquery.mousewheel": "../vendor/jquery.mousewheel/jquery.mousewheel",
"jquery.jscrollpane": "../vendor/jquery.jscrollpane/jquery.jscrollpane"
},
shim: {
'backbone': {
deps: ['underscore']
},
'layoutmanager': {
deps: ['backbone', 'lodash', 'ldsh']
},
'jquery.transit': {
deps: ['jquery']
},
'json': {
deps: ['text']
}
}});
// App initialization
require(["app"], function(instance) {
"use strict";
window.app = instance;
app.load();
});
And finally, my dev/app.js file:
define(function(require, exports, module) {
"use strict";
// External global dependencies.
var _ = require("underscore"),
$ = require("jquery"),
Transit = require('jquery.transit'),
Backbone = require("backbone"),
Layout = require("layoutmanager");
module.exports = {
'layout': null,
'load': function() {
var paths = [
// ***
// *** 1- define its path
// ***
'json!config/main.json',
'modules/nav',
'modules/store',
'modules/utils',
'modules/preloader',
'modules/popup',
'modules/login',
'modules/user',
'modules/footer',
];
try {
require(paths, function(
// ***
// *** 2- call it a name
// ***
Config,
Nav,
Store,
Utils,
Preloader,
Popup,
Login,
User,
Footer
) {
// ***
// *** 3- instance it in the app
// ***
app.Config = Config;
app.Nav = Nav;
app.Store = Store;
app.Utils = Utils;
app.Preloader = Preloader;
app.Popup = Popup;
app.Login = Login;
app.User = User;
app.Footer = Footer;
// require and instance the router
require(['router'], function(Router) {
// app configuration
app.configure();
// app initialization
app.Router = new Router();
});
});
} catch (e) {
console.error(e);
}
},
'configure': function() {
var that = this;
// set environment
this.Config.env = 'local';
// Ajax global settings
Backbone.$.ajaxSetup({
'url': that.Config.envs[that.Config.env].core,
'timeout': 90000,
'beforeSend': function() {
},
'complete': function(xhr, textstatus) {
}
});
// Template & layout
_.templateSettings = {
interpolate: /\{\{(.+?)\}\}/g
};
Layout.configure({
// Allow LayoutManager to augment Backbone.View.prototype.
manage: true,
// Indicate where templates are stored.
prefix: "app/templates/",
// This custom fetch method will load pre-compiled templates or fetch them
// remotely with AJAX.
fetch: function(path) {
// Concatenate the file extension.
path = path + ".html";
// If cached, use the compiled template.
if (window.JST && window.JST[path]) {
return window.JST[path];
}
// Put fetch into `async-mode`.
var done = this.async();
// Seek out the template asynchronously.
$.get('/' + path, function(contents) {
window.JST[path] = contents;
done(_.template(contents));
}, "text");
}
});
},
};
});
Any ideas why is that json module not "required" when executing grunt requirejs ?
Thanks in advance.
Not sure if this is still an issue, but from the requirejs optimizer docs (http://requirejs.org/docs/optimization.html):
The optimizer will only combine modules that are specified in arrays of string literals that are passed to top-level require and define calls, or the require('name') string literal calls in a simplified CommonJS wrapping. So, it will not find modules that are loaded via a variable name...
It sounds like the requirejs optimizer doesn't like the require calls being made with a variable that is an array of dependencies.
It also sounds like the requirejs optimizer doesn't like the syntax of require([dependency array], callback) being used within the actual file being optimized.
You may have to refactor your dependency declarations within dev/app.js to conform to this specification. For example, you might be able to use the following refactoring of steps 1 and 2:
var Config = require('json!config/main.json');
var Nav = require('modules/nav');
var Store = require('modules/store');
var Utils = require('modules/utils');
var Preloader = require('modules/preloader');
var Popup = require('modules/popup');
var Login = require('modules/login');
var User = require('modules/user');
var Footer = require('modules/footer');
If this does work, it looks like you'll also have to do something similar for the Router dependency declaration.
Also, a minor addition that you might want to include to your requirejs configuration once you get it running is:
stubModules : ['json']
Since the built file should have the JSON object within it, you won't even need the plugin within the built file! As such, you can reduce your file size by removing the json plugin from it.

Create PDF with NodeJS, Jade and PhantomJS

I want to create a PDF from a template in Jade using PhantomJS, I can create the PDF document, but the CSS is not applying, I create two routes the first one render the template to the web browser and the second one generate de PDF with the exact same jade template, in the browser all is right, but the PDF don't apply CSS.
My app.js is:
var express = require('express'),
routes = require('./routes'),
http = require('http'),
path = require('path'),
bodyParser = require('body-parser');
var app = express();
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(express.static(path.join(__dirname, 'public')));
app.post('/api/cotizacion/generar', routes.cotizacion.generar);
app.get('/api/cotizacion/generar', routes.cotizacion.testGenerar);
app.all('*', function(req, res) {
res.send(404);
});
http.createServer(app).listen(app.get('port'), function(){
console.info('Express server listening on port ' + app.get('port'));
});
The controller file is cotizacion.js:
var phantom = require('phantom');
exports.generar = function(req, res, next){
if(!req.body.cotizacion){
return next(new Error('No se enviaron datos de cotización'));
}
var cotizacion = req.body.cotizacion;
req.app.render('test', {cotizacion: cotizacion}, function(err, html){
generarPDF(cotizacion, html, function(){
res.send("1");
});
});
};
exports.testGenerar = function(req, res, next){
res.render('test', {});
};
generarPDF = function(cotizacion, html, callback){
phantom.create(function(ph){
ph.createPage(function(page){
page.set('paperSize', { format: 'Letter' });
page.set('content', html);
page.render(__dirname + '/test.pdf', function(err){
ph.exit();
callback();
});
});
});
}
And finally my test.jade is:
doctype html
html
head
title Cotización PDF
link(rel='stylesheet', href='/css/pdf.css')
body
h1 Test
The following works, but is a little annoying
doctype html
html
head
title Cotización PDF
| <style type="text/css">
| body{ color: green; }
| </style>
body
h1 Test
The project structure is:
/
app.js
public/
css/
pdf.css
routes/
index.js
cotizador.js
views/
test.jade
Ok here is our solution for similar problem. Below JADE template, notice hrefs with a reference to JSON object properties:
doctype html
html(lang="en")
head
link(rel='stylesheet', type="text/css", media="all", href=report.statics.bootstrap)
link(rel='stylesheet', type="text/css", media="all", href=report.statics.custom)
body
Here is a code snippet, used for providing to the template CSS paths:
var createStatics = function (req) {
var hostName = url.format({protocol: req.protocol,
host: req.get('host')
});
return {
bootstrap: hostName + '/assets/reports/bootstrap-report.css',
custom: hostName + '/assets/reports/custom.css',
}
}
Next here is a JADE template compilation:
var fn = jade.compile(template);
Transportation object, used for passing required by JADE template utility objects:
var report = {
statics: statics,
title: 'Simple report title'
};
Rendering HTML report and retrieved as a stream...
var output = fn({
report: report
});

Resources