Call function from Dust template - node.js

I'm developing a simple web site where I need to retrieve a list of objects from a database. I wanted to try nodejs so, after days of reading and tests, I finally decided to use this configuration:
Server technology: Nodejs + Express
Template engine: Dust
Database/Data source: Parse
I wired all these stuff and it seems working well, but I have now the first problem: I need to call a function from a Dust template, this is the code:
{>layout/}
{<content}
<ul>
{#photos}
<li>{photo.get("name")}{~n}</li>
{/photos}
</ul>
{/content}
but it doesn't work because it prints out {photo.get("name")} (literally) instead of printing the name of each photo. The query with Parse works correctly as I can see the loaded objects via console.log().
I'm new both with nodejs and dust so I'm not sure the problem is related only to dust. Any idea?

I have no any other solution except creation of a helper:
var dust = require('dustjs-linkedin');
dust.helpers.exec = function(chunk, context, bodies, params) {
var args = JSON.parse(params.args.replace(/'/g, '"'));
var object = context.stack.head;
params.func.split('.').some(function(property) {
if (typeof(object[property]) === "function") {
var result = object[property].apply(object, args);
chunk.write(result);
return true;
} else {
object = object[property];
return false;
}
})
return chunk;
};
Suppose we have following data:
app.get('/dust-test', function(req, res) {
function Photo(name) {
var props = {'name': name};
this.get = function(prop) {
return props[prop];
}
}
var photos = ['foo', 'bar', 'nanana'].map(function(name) {
return new Photo(name);
})
res.render("dust-test", {
photo: new Photo('me'),
photos: photos
});
});
Usage:
<li>{#exec func="photo.get" args="['name']" /}</li>
{#photo}
<li>{#exec func="get" args="['name']" /}</li>
{/photo}
<ul>
{#photos}
<li>{#exec func="get" args="['name']" /}{~n}</li>
{/photos}
</ul>
Where args - is an array of arguments in json format (single quotes are used)

Related

Cheerio scraping returning only two rows

So I tested my scraping on a static HTML file before adding it to my Node app.
The problem is that it's not returning all the rows.
On the site:
$('#sport tr').length
//Returns 13
In Cheerio:
$('#sport tr').length
//Returns 2
I'm stumped, here is the code I'm using. I've contained the URL as proof, so you can visit it yourself if you wish.
I'm suspecting it's something to do with var $ = cheerio.load(html); however I'm not experienced in Cheerio to say outright that's the problem.
var express = require('express');
var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');
var app = express();
app.get('/scrape', function(req, res){
var url = 'http://www.olbg.com/football.php';
var json = [];
request(url, function(error, response, html){
if(!error){
var $ = cheerio.load(html);
console.log($('#sport tr').length);
var headers = [];
$('#sport tr th').each(function(i, th) {
var text = $(th).text();
if (text.trim() !== "") {
headers[i] = text.replace(/[\t\n\r\s]/mgi, '');
}
});
$('#sport tr').each(function(i, tr) {
// skip if header
if (!$(tr).is('th')) {
var temp = {};
temp["Event"] = $(tr).find('td').eq(0).text().trim();
temp["TopSelection"] = $(tr).find('td').eq(1).text().trim();
temp["BookieOdds"] = $(tr).find('td').eq(2).text().trim();
temp["OLBGRating"] = $(tr).find('td').eq(3).find('img').length;
if (temp["Event"] !== "" || temp["TopSelection"] !== ""){
json.push(temp);
}
}
});
}
// To write to the system we will use the built in 'fs' library.
// In this example we will pass 3 parameters to the writeFile function
// Parameter 1 : output.json - this is what the created filename will be called
// Parameter 2 : JSON.stringify(json, null, 4) - the data to write, here we do an extra step by calling JSON.stringify to make our JSON easier to read
// Parameter 3 : callback function - a callback function to let us know the status of our function
fs.writeFile('output.json', JSON.stringify(json), function(err){
console.log('File successfully written!');
})
// Finally, we'll just send out a message to the browser reminding you that this app does not have a UI.
res.send(json);
});
});
app.listen("8081");
console.log("Magic happens on port 8081");
exports = module.exports = app;
The reason that you're not getting the expected result is because the (table) html on that page is mangled. If you look at the second <td> in the second <tr> of the table#sport, you'll see an "extra" </td>. This causes the <td> that the table#sport is inside to close (and an implicit closing of table#sport) on some parsers because that is the closest open <td>. So that is why the parser reports only 2 <tr>s instead of 13. The other <tr>s you're expecting are now outside of table#sport.
Probably your best bet is to pass the html through an HTML tidying program/script (e.g. this one with the clean option enabled) first before passing it to cheerio. After that, your selector should return the elements you're probably expecting.

node js (with ejs view engine) give undefined variable on the view

I've been working on this for a few hours now but still can't get anywhere. I have a view that tries to create a geojson file on the fly and return it to the node view as a variable. The variable is not empty before it hits the res.render line but when it the view gets loaded, the result is always undefined.
app.get('mymap', function(req, res, next){
var featureCollection= {
type : 'FeatureCollection',
features : new Array()
};
Shapes.find({'id' : 778899}, function(err, data){
data.forEach(function(d){
collection.features.push(d);
});
res.render('mymap.ejs', { geojson: featureCollection});
});
});
this is where i call to see if there's something on the view
var mymap = '<%- geojson%>';
alert('Current values ' + mymap.type);
Not really sure what's wrong.. I even tried to just make up a variable with multiple properties, eg:
var test = { place: 'Here and There', size : 5555 }
res.render ('mymap.ejs', { geojson: test });
Still nothing happens.
Well, you had a typo in your code:
var mymap = '<%- geojson%>';
It should be:
var mymap = '<%= geojson %>';
More precisely, if you want to read a Javascript Object from server-side, I suggest to pass it as a JSON string:
var mymap = JSON.parse('<%= JSON.stringify(geojson) %>');

How to use templating (handlebars, or any alternative) with Node.js and without using a framework (ex = express)?

For example, I have this JSON document "foo.json":
{
"foo": [
{
"bar": "Hello World!"
},
{
"bar": "The End"
}
]
}
In Node.js, I would like to use templating (handlebars or any) to generate a string from the JSON document, such as:
<p>Hello World!</p><p>The End</p>
... And then assign that string value to a variable in Node.js. Finally, I'll concatenate more values to the variable and output the final variable value as an html document.
Can this be done without using a framework like Express?
If you want to use handlebars, just grab the npm module:
npm install handlebars
Then in your script, you can use handlebars to render your output based on a simple template that iterates over the array foo and creates a <p> for each item, containing the text of the bar property:
var handlebars = require('handlebars');
// get your data into a variable
var fooJson = require('foo.json');
// set up your handlebars template
var source = '{{#each foo}}<p>{{this.bar}}</p>{{/each}}';
// compile the template
var template = handlebars.compile(source);
// call template as a function, passing in your data as the context
var outputString = template(fooJson);
If you want to use a .hbs template file instead of a string source you can use the fs module to read the file with fs.readFile, call toString() on the returned buffer, and use that to call a rendering function. Try this:
var handlebars = require('handlebars');
var fs = require('fs');
// get your data into a variable
var fooJson = require('path/to/foo.json');
// read the file and use the callback to render
fs.readFile('path/to/source.hbs', function(err, data){
if (!err) {
// make the buffer into a string
var source = data.toString();
// call the render function
renderToString(source, fooJson);
} else {
// handle file read error
}
});
// this will be called after the file is read
function renderToString(source, data) {
var template = handlebars.compile(source);
var outputString = template(data);
return outputString;
}

Where to access and store EJS Helpers - SailsJS

Well,
SailJS's default templateing engine is EJS (Embedded Javascript)
But I cannot seem to find the place where we can create our own helpers and stuff.
So, do you know where to access & store EJS helpers/stuff?
solved:
https://github.com/balderdashy/sails/issues/2162#issuecomment-55866731
config/http.js
module.exports.http = {
// ...
locals: {
filters: {
formatDate: function(date) { }
}
}
}
config/bootstrap.js
_.extend(sails.hooks.http.app.locals, sails.config.http.locals);
At some view...
views/test.ejs
<%=: created | formatDate %>
You should create file in ./config with name anyname.js and write some EJS helper like these code:
var moment = require('moment');
var ejs = require('ejs');
ejs.filters.fromNow = function(date){
return moment(date).fromNow()
}
ejs.filters.formatDate = function(date){
return moment(date).format('MMM Do YYYY');
}
ejs.open = '<?';
ejs.close = '?>';
Then in layout, view, it should be call
<td><?=: post.createdAt | formatDate ?></td>
Hope that help!
Update
For some reasons, you guys have to install module sails locally to make sense. So just paste to your console:
npm i sails
regards,
Anh Nguyen
One way to accomplish this is through middleware. Something like:
module.exports.routes = {
'*': function mixinForm(req, res, next) {
// <%= form() %>
res.locals.form = function () {
return '<form action=""></form>';
};
next();
},
}
I would also suggest making a feature request for a more integrated approach at: https://trello.com/b/cGzNVE0b/sails-js-feature-requests.

How to read image from Application folder in winjs

How to read image from Application folder in winjs
var item = groupedProducts.getAt(indx);
item.img = Windows.Storage.ApplicationData.current.localFolder.path + "\\" + "3766111.jpg";
groupedProducts.setAt(indx, item);
WinJS.UI.processAll();
You need to use the async APIs to access files in ApplicationData in WinJS, such as the getFileAsync function used below (this is a helper function I use in databinding for one of my apps):
function getLocalLargeMapTile(item) {
return new WinJS.Promise(
function (completed, error, progress) {
var filename;
var sourceFolder;
if (item.latlong) {
var latandlong = item.latlong.split(", ");
var lat = latandlong[0];
var lon = latandlong[1];
filename = lat + lon + ".png";
var appData = Windows.Storage.ApplicationData.current;
sourceFolder = appData.localFolder;
sourceFolder.getFileAsync(filename).then(function (file) {
var mapUrl = window.URL.createObjectURL(file, { oneTimeOnly: true });
completed(mapUrl);
},
function (error) {
handleError(error)
});
}
else {
filename = "ms-appx:///images/megaphone_256x256.png";
completed(filename);
}
}
);
}
What I'm doing in the helper function is checking whether my data includes a latitude and longitude, and if so, checking for a file with a matching filename, and since those files are in the Application Data folder, wrapping the file with an objectURL and returning a promise with the objectURL. Otherwise, I simply return an ms-appx url pointing to a static file in the app's images folder. Here's how I call this helper function, from a programmatic template (I don't think you can do this with a declarative template):
var image = document.createElement("img");
image.className = "item-image";
image.src = "ms-appx:///images/megaphone_256x256.png";
result.appendChild(image);
// additional code omitted
var promise = mapTileUtil.getLocalMapTile(currentItem);
promise.done(function (mapTileUrl) {
image.src = mapTileUrl;
});
For more info on templating functions, which provide greater control over the rendered markup than declarative templates, check out:
http://msdn.microsoft.com/en-us/library/windows/apps/jj585523.aspx
and
http://go.microsoft.com/fwlink/p/?linkid=231499
For more information on Windows Store app development in general, register for App Builder.

Resources