As mentioned in title, when data is referenced inside of the html template it is undefined.
JS:
var data = [];
for (var i = 0; i < rows.length; i++) {
data.push(rows[i]);
if (i == rows.length - 1) {
fs.readFile('tree.html', 'utf8', function (err, html) {
console.log(data);
var template = _.template(html);
var result = template({ data: data });
res.send(result);
});
}
}
HTML:
<html xmlns="http://www.w3.org/1999/xhtml"><head>
<title></title>
</head>
<body>
<%
console.log(data);
%>
</body>
</html>
I'm new to underscore, but it works fine for me. Check what you've missed.
File Structure:
--test.html
--test.js
test.html
<html xmlns="http://www.w3.org/1999/xhtml"><head>
<title></title>
</head>
<body>
<%
console.log(data, 'it works! ');
%>
</body>
</html>
test.js
var data = [], rows = [1,2,3,4];
var _ = require('underscore'),
fs = require('fs');
for (var i = 0; i < rows.length; i++) {
data.push(rows[i]);
if (i == rows.length - 1) {
fs.readFile('test.html', 'utf8', function(err, html) {
console.log(html); // correct html file content
var template = _.template(html);
var result = template({
data: data // After console print the html file,
// it runs the script code in html file,
// which in my point of view, means `template` works.
});
// res.send(result);
});
}
}
Run node test.js in the terminal, it works fine.
PS: I did console.log(result) and got the correct result:
<html xmlns="http://www.w3.org/1999/xhtml"><head>
<title></title>
</head>
<body>
</body>
</html>
Related
So, this is my JS code:
function main(){
let myJSON = parseCSV();
console.log(myJSON);
let myCSV = transformCSV(myJSON);
console.log(myCSV);
}
function parseCSV(){
let parsedJSON;
let selectedFile = document.getElementById('fileIn').files[0];
Papa.parse(selectedFile, {
complete: function(results) {
parsedJSON = results.data;
console.log(results.data);
console.log(typeof(results.data));
}
});
return parsedJSON;
}
function transformCSV(JSONIn){
let csvOut = ""; // i will do something here later
let dCol = ""; // i will do something here later
let dRow = ""; // i will do something here later
for (let i = 0; i < JSONIn.length - 1; i++) {
// i will do something here later
}
return csvOut;
}
And this is my test html page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src=".\transformCSV.js"></script>
<script src=".\node_modules\papaparse\papaparse.js"></script>
<input type="file" id="fileIn">
<input type="button" value="click!" onclick="main()">
</body>
</html>
When I try to read length of myJSON, I get error message in Chrome console: Uncaught TypeError: Cannot read property 'length' of undefined. Why is it undefined? It is present in console! Why does this happen and how to fix it? How to work with resulted myJSON as a perfectly normal static JSON?
You set the value of parsedJSON in the complete callback function. This will probably be called AFTER your function parseCSV has returned the undefined value of parsedJSON. You need to rewrite it with a callback or promise.
parseCSV(function (myJSON) {
console.log(myJSON);
let myCSV = transformCSV(myJSON);
console.log(myCSV);
});
function parseCSV(callback){
let parsedJSON;
let selectedFile = document.getElementById('fileIn').files[0];
Papa.parse(selectedFile, {
complete: function(results) {
parsedJSON = results.data;
callback(parsedJSON);
}
});
}
I'm trying to load a local .json file in my NodeJS application and loop through the items, loading them in a ordered list. I've created my main js file and the model for the data, plus the main html page but I get a strange error. I receive document not defined in my data.js file:
document.getElementById('update').appendChild(makeUl(dataObject));
Here is my main js file, app.js:
var express = require('express' );
var app = express();
var bodyParser = require('body-parser');
app.use(express.static(__dirname+ '/client'));
app.use(bodyParser.json());
var Data = require('./models/data.js');
app.get('/', function(req,res){
res.send("Please use /api/data");
});
app.get('/api/data',function(req, res){
Data.getData(function(err, data){
if (err){
throw err;
}
res.json(data);
});
});
app.listen(5000);
console.log('Connected');
and here is my data.js file where I receive the error:
var dataObject = require("../jsondata/reduced_dataset.json");
function makeUL(array) {
// Create the list element:
var list = document.createElement('ul');
for(var i = 0; i < array.length; i++) {
// Create the list item:
var item = document.createElement('li');
// Set its contents:
item.appendChild(document.createTextNode(array[i]));
// Add it to the list:
list.appendChild(item);
}
// Finally, return the constructed list:
return list;
}
document.getElementById('update').appendChild(makeUL(dataObject));
I don't understand why I receive this error since I've linked it in the html page:
<html>
<head>
<title>Data Parsing</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<div id = "update"> </div>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="app.js"></script>
<script src ="./models/data.js"></script>
</body>
</html>
I used to use mustache.js for my templates on a quickbase app, but recently decided to switch over to trying handlebars so that I could use the if/then of it for a more appealing template.
However I can not seem to get them to work like mustache did, the Get for my module.js shows in the console, but after that the page doesn't load like it's supposed to (it usually loads the template.html)
module.js
var dbidApplication = "dbidHere";
var dbidTable = "dbidtHere";
var apptoken = "apptokenhere";
$.ajaxSetup({
data: {
apptoken: apptoken
}
});
var promise1 = $.get(dbidApplication, {
a: "dbpage",
pagename: "template.html"
});
var promise2 = $.get(dbidTable, {
act: "API_GenResultsTable",
query: "{3.EX." + kRid + "}",
jsa: 1,
options: "num-1",
});
$.when(promise1, promise2).then(function(html, data) {
//do some stuff with all the data
var template = Handlebars.compile(html[0]);
console.log(html[0]);
console.log(data[0]);
console.log(qdb_data);
$(template(qdb_data)).appendTo("#external");
});
My template has the source for handlebars and the div with id external
template.html
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.3/handlebars.runtime.min.js" type="text/javascript"></script>
<title></title>
</head>
<body>
<div id="external"></div>
</body>
</html>
I think you forgot to set qdb_data:
$.when(promise1, promise2).then(function(html, data) {
//do some stuff with all the data
var template = Handlebars.compile(html[0]);
var qdb_data = data[0];
console.log(html[0]);
console.log(data[0]);
console.log(qdb_data);
$(template(qdb_data)).appendTo("#external");
});
Intro
I'm trying to create an aggregate file with all of my UnderscoreJS templates in it. I'll explain how I've achieved this with a JSP app with a Java backend.
How I got it working in my JSP app:
When using jsp pages, you're able to do:
<html>
<head> ... </head>
<body>
...
<jsp:include page="./path/to/aggregate_templates.jsp"/>
</body>
</html>
And in this file, you can have all of your UnderscoreJS templates listed like so:
<jsp:include page="./path/to/js/view/home/file.template"/>
<jsp:include page="./path/to/js/view/home/file2.template"/>
...
Question
Rather than a Java backend, I'm using a NodeJS server. Is there a way I can have an aggregate template file on the fly that does the same thing as jsp:include? Or is my only option something like this: Templating using RequireJS (text.js plugin) and Underscore?
The solution:
Append all *.template files together with fileUtil.aggregateTemplates() into aggregate.template
When index.html is loaded in the browser, main.js runs
Before doing anything else, main.js calls TemplateCache.setup()
TemplateCache.setup() adds the contents of aggregate.template to $("#templates")
All templates are now in the html and at the Backbone views' disposal
The code:
In app.js
...
var fileUtil = require('./utils/file-util');
var aggregateTemplateFile = 'path/to/aggregate.template';
var targetDir = 'path/to/directory/containing/template/files';
fileUtil.aggregateTemplates(targetDir, aggregateTemplateFile);
...
In file-util.js
var fs = require('fs');
var path = require('path');
/**
* Traverse the directory
* #param dir - directory to traverse
* #param cond - callback for determining whether or not to keep file
* #param done - callback for what to do with results
*/
var walk = function(dir, cond, done){
var results = [];
fs.readdir(dir, function(err, list){
if(err){
return done(err);
}
var i = 0;
(function next(){
var file = list[i++];
if(!file){
return done(null, results);
}
file = path.resolve(dir, file);
fs.stat(file, function(err, stat){
if(stat && stat.isDirectory()){
walk(file, cond, function(err, res){
results = results.concat(res);
next();
});
}else{
if(cond(file)){
results.push(file);
}
next();
}
});
})();
});
};
/**
* Create aggregate file
* #param fileArr - array of files (full path)
* #param targetFile - file to print to (full path)
* #param strictOrder - (optional) boolean whether or not to enforce order
*/
var createAggregate = function(fileArr, targetFile, strictOrder){
if(!fileArr || fileArr.length<1){
return;
}
fs.writeFileSync(targetFile, ""); // clear file
if(strictOrder){
var i = 0;
(function next(){
var file = fileArr[i++];
if(!file){
return;
}
fs.readFile(file, function(err, data){
if(err) throw err;
fs.appendFileSync(targetFile, data);
next();
});
})();
return;
}
for(var i=0; i<fileArr.length; i++){
var file = fileArr[i];
fs.readFile(file, function(err, data){
if(err) throw err;
fs.appendFileSync(targetFile, data);
});
}
};
/**
* Create an aggregate template file
* #param targetDir - directory to look in (full path)
* #param targetFile - file to print to (full path)
*/
exports.aggregateTemplates = function(targetDir, targetFile){
// Determine what kind of files we care about
var isTemplate = function(file){
return file.match(/.+\.template$/);
};
// Determine what we do with the results
var done = function(err, result){
if(err) throw err;
createAggregate(result, targetFile);
};
// Traverse the target directory
walk(targetDir, isTemplate, done);
};
In index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>MyApp</title>
<link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.css">
<link rel="stylesheet" href="/lib/bootstrap/css/bootstrap-custom.css">
<link rel="stylesheet" href="/lib/font-awesome/css/font-awesome.css">
<link rel="stylesheet" href="/stylesheets/style.css">
<link rel="stylesheet" href="/stylesheets/style-responsive.css">
</head>
<body class="center-on-page">
<div id="header" class="affix"></div>
<div id="content"></div>
<div id="javascript">
<!-- JavaScript Library Imports -->
<!-- JavaScript Local Imports -->
<!-- Code Entry Point -->
<script type="text/javascript" src="/js/main.js"></script>
</div>
<!-- Underscore Templates -->
<div id="templates"></div>
</body>
</html>
In main.js
(function(){
$.when(app.util.TemplateCache.setup())
.done(function(){
// Start the router
new app.Router();
Backbone.history.start();
});
})();
app.util.TemplateCache.setup
app.util.TemplateCache.setup = function(){
var opts = { url: "aggregate.template" };
return $.ajax(opts)
.done(function(data, textStatus, jqxhr){
console.log("Loaded aggregate template file");
$("#templates").html(data);
})
.fail(function(data, textStatus, jqxhr){
console.log("Failed to load aggregate template file");
});
};
what's wrong here?
OPTIONS https://twitter.com/oauth/request_token 401 (Unauthorized)
jsOAuth-1.3.4.js:483 XMLHttpRequest cannot load
https://twitter.com/oauth/request_token. Origin "http://localhost:8080"
is not allowed by Access-Control-Allow-Origin.Object
<!DOCTYPE html>
<html>
<head>
<!--
A simple example of PIN-based oauth flow with Twitter and jsOAuth.
This is mostly based on/copied from <http://log.coffeesounds.com/oauth-and-pin-based-authorization-in-javascri>.
Get jsOAuth at <https://github.com/bytespider/jsOAuth/downloads>
-->
<meta charset="utf-8">
<title>jsOauth test</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script type="text/javascript" src="jsOAuth-1.3.4.js"></script>
<style type="text/css" media="screen">
</style>
<script>
$(document).ready(function() {
var options = {
consumerKey: 'YOUR_CONSUMER_KEY',
consumerSecret: 'YOUR_CONSUMER_SECRET'
};
var requestParams;
var accessParams;
var oauth = OAuth(options);
oauth.get('https://twitter.com/oauth/request_token',
function(data) {
console.dir(data);
window.open('https://twitter.com/oauth/authorize?'+data.text);
requestParams = data.text
},
function(data) { alert('darn'); console.dir(data) }
);
$('#pinbutton').click(function() {
if ($('#pin').val()) {
oauth.get('https://twitter.com/oauth/access_token?oauth_verifier='+$('#pin').val()+'&'+requestParams,
function(data) {
console.dir(data);
// split the query string as needed
var accessParams = {};
var qvars_tmp = data.text.split('&');
for (var i = 0; i < qvars_tmp.length; i++) {;
var y = qvars_tmp[i].split('=');
accessParams[y[0]] = decodeURIComponent(y[1]);
};
oauth.setAccessToken([accessParams.oauth_token, accessParams.oauth_token_secret]);
getHomeTimeline();
},
function(data) { alert('poop'); console.dir(data); }
);
}
});
function getHomeTimeline() {
oauth.get('https://api.twitter.com/1/statuses/home_timeline.json',
function(data) {
entries = JSON.parse(data.text);
var html = [];
for (var i = 0; i < entries.length; i++) {
html.push(JSON.stringify(entries[i]));
};
$('#timeline').html(html.join('<hr>'));
},
function(data) { alert('lame'); console.dir(data); }
);
}
});
</script>
</head>
<body>
<h1>jsOauth test</h1>
When you get a PIN, enter it here.
<input id="pin" type="text" value=""><button id='pinbutton'>Save</button>
<div id="timeline">
</div>
</body>
</html>
I could give you the answer, but what you're doing is against the Twitter API Terms of Service. OAuthing in JavaScript exposes the secret credentials to anyone who visits the site and that is A Bad Thing. Please do this on your back-end.