I have split the STDOUT of a shell command into an array, and am passing this to hogan view engine with express.
The below is the from the router file - index.js
/* Test Shell Execute. */
router.get('/shell', function(req, res){
exec('ls -1', function (error, stdout, stderr) {
result = stdout.toString().split("\n");
res.render('shell', { title: "File Explorer",
array1: result[0],
array2: result[1],
array3: result[2],
array4: result[3],
array5: result[4],
error: error,
stderr: stderr
});
});
});
This is working fine, however rather than manually send through each item in the array, I would like to iterate through the items at the view end and then ouput. However I am using Hogan view engine and it doesn't seem to recognise the script tag at all.
This is from my view shell.hjs file.
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<h1>{{ title }}</h1>
<p>Welcome to {{ title }}</p>
<p>Array1 = {{ array1 }}</p>
<p>Array2 = {{ array2 }}</p>
<p>Array3 = {{ array3 }}</p>
<p>Array4 = {{ array4 }}</p>
<script>
for(var i = 0; i > result.length; i++ ) {
document.write('<p>' + result[i] + '</p>')
}
</script>
</body>
</html>
Question: What am I doing wrong and what is the best/easiest way to do this?
Since hogan.js is based on mustache.js, it's always better try to convert your arrays into objects. Try this:
router.get('/shell', function(req, res){
exec('ls -1', function (error, stdout, stderr) {
result = stdout.split("\n"),
filesArray = [];
result.map(function (file, index) {
filesArray.push({index: ++index, file: file});
});
res.render('shell', { title: "File Explorer",
result: filesArray,
error: error,
stderr: stderr
});
});
});
And, in your template:
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<h1>{{ title }}</h1>
<p>Welcome to {{ title }}</p>
<ul>
{{#result}}
<li>Array{{index}} = {{file}}</li>
{{/result}}
</ul>
</body>
</html>
Related
I have following code in my project:
<template>
<div>
<Head>
<Title>{{ story.title}}</Title>
<Meta name="description" content="product.description" />
</Head>
<StoryDetails :story="story" />
<button class="btn">
<NuxtLink to="/">Back to home</NuxtLink>
</button>
</div>
</template>
scripts:
<script setup>
definePageMeta({
layout: "stories"
})
const { id } = useRoute().params
const uri = 'https://hacker-news.firebaseio.com/v0/item/'+ id +'.json?print=pretty'
const { data: story } = await useFetch(uri, { key:id })
const { data: comments} = []
if(!this.story.value) {
throw createError({ statusCode: 404, statusMessage: 'Story not found!', fatal: true })
}
this.story.kids.forEach(id => {
$fetch('https://hacker-news.firebaseio.com/v0/item/'+ id +'.json?print=pretty')
.then((response) => {
this.comments.push(response)
console.log(this.comments)
})
.catch(err=> {q
this.err = err
})
})
console.log(this.comments)
</script>
Please, help. How can I display comments (nested kids also) ?
I am getting this error for code above:
GET http://localhost:3000/_nuxt/pages/[id].vue?vue&type=style&index=0&scoped=dd4001d8&lang.css net::ERR_ABORTED 404 (Page not found: /_nuxt/pages/[id].vue?vue&type=style&index=0&scoped=dd4001d8&lang.css)
My github repo: https://github.com/AzizxonZufarov/newsnuxt2/blob/main/pages/%5Bid%5D.vue
PS: Also I am getting this error:
[plugin:vite:css] [postcss] C:/Users/Acer/Desktop/newsnuxt/pages/[id].vue?vue&type=style&index=0&scoped=dd4001d8&lang.css:4:15: Unknown word
C:/Users/Acer/Desktop/newsnuxt/pages/[id].vue:4:15
2 | <div>
3 | <Head>
4 | <Title>{{ story.title}}</Title>
| ^
5 | <Meta name="description" content="product.description" />
6 | </Head>
So i am trying to get a first_name from JSON object which has array of elements by iterating through it, for example if i type 'Ron' it will display as a text but for some reason I can't get display it as a text unless i send in a respond this `
playerName: nbaPlayer[0]
But it only displays one element as a text since others are not in a response
reponse in a server enter image description here
Here is a code for fetch where i use search bar from handlebars to search for a first_name
const nbaForm = document.querySelector('form')
const search = document.querySelector('input')
const messageOne = document.querySelector('#player-1')
nbaForm.addEventListener('submit', (event) => {
event.preventDefault()
const playerSearch = search.value
messageOne.textContent = 'Loading...'
fetch('http://localhost:4000/nba').then((response) => {
response.json().then(nbaData => {
if (nbaData.playerName === playerSearch) {
messageOne.textContent = nbaData.playerName
} else {
messageOne.textContent = 'not found'
}
})
})
})
request method
app.get('/nba', (req,res) => {
networkManager.nbaPlayerData((data)=>{
/
var nbaPlayer = []
for(var i=0; i<data.data.length; i++){
nbaPlayer.push(data.data[i].first_name)
}
console.log(nbaPlayer)
res.send({
playerName: nbaPlayer
})
})
})
handlebars file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NBA</title>
<link rel = "stylesheet" href="/css/style.css">
</head>
<body>
<div class="main-content">
<h1>NBA SERVER</h1>
<p>Use this site to get NBA player</p>
<form action="">
<input placeholder="Type a players name">
<button>Search</button>
</form>
<p id="player-1"></p>
<h1>{{playerName}}</h1>
</div>
<script src ="/js/fetch-app.js"></script>
</body>
</html>
try this.
fetch('http://localhost:4000/nba').then((response) => {
response.json().then(nbaData => {
var index = nbaData.playerName.indexOf(playerSearch)
if (index !== -1) {
messageOne.textContent = nbaData.playerName[index]
} else {
messageOne.textContent = 'not found'
}
})
})
You are getting an array from
res.send({
playerName: nbaPlayer // nbaPlayer is array
})
but in your fetch, you want to get data as from simple object
As you can see I included my navbar component in my index.ejs file and I am doing the same thing with every other file I have, like user page for example. Is there any way that I can use my navbar component in all of my ejs files by including it somewhere once? instead of including it separately in each ejs file?
Right now I am doing this in every one of my files:
index.ejs:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<% include components/navbar %>
rest of the code...
</body>
</html>
as you requested in comments , this is my way to do it :
i have "views" folder in project including these folders inside :
Assets
Layouts
and dynamic ejs files beside them
let's say we want to render this layout which has a header in each page , but with different body :
layout :
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<% for (let cssLink of cssLinks) { %>
<link rel="stylesheet" href="<%= cssLink %>" />
<% } %>
<title>home page</title>
</head>
<body>
<h1>THIS IS HEADER!</h1>
<div id="demo">
<%- mainView %>
</div>
</body>
</html>
you can see there is a variable mainView in the body , so let's see how can we insert our dynamic body there :
i have a function inside my utility folder which reduces the repeat of code :
const ejs = require('ejs');
const path = require('path');
const layoutsPath = path.join(__dirname, "./../views/layouts/");
const assetsPath = path.join(__dirname, "./../views/assets/");
const viewsPath = path.join(__dirname, './../views/');
const load = (basePath, filename, data, cb = null) => {
let route ;
switch (basePath) {
case 'layout': {
route = layoutsPath;
break;
}
case 'asset': {
route = assetsPath;
break;
}
case 'view': {
route = viewsPath;
break;
}
default: {
route = basePath;
}
}
ejs.renderFile(path.join(route, filename), data, (err, str) => {
if (err) {
console.log(err);
return err;
}
if (cb === null) {
return str;
} else {
return cb(str);
}
});
}
module.exports = {
load
}
now in the index.js i want to output my home.ejs inside my header.ejs to the client :
let allUsers = await usersModule.findAll();
let renderedHTML = '';
load('view', 'home.ejs', { allUsers }, (rendered) => {
load('layout', 'header.ejs', { mainView: rendered, cssLinks: ['/css/header.css'] }, (fullView) => {
renderedHTML = fullView;
});
});
res.status(200).send(renderedHTML);
so here i am getting my required data for my body from database , passing it to the home.ejs , there i loop and render my body view , e.x for home.ejs :
<div>
<% for (let user of allUsers) { %>
<ul>
<li>email : <%= user.email %></li>
<li>name : <%= user.name %></li>
</ul>
<% } %>
</div>
rendered body is passed to our callback as parameter , we can pass it to our header now with variablename mainView , so in the header, the entire rendered body will be insert in the right place in our layout .
now our layout and dynamic body have merged and are ready to be sent to the client
I am creating a simple rest api in javascript, I want upon initialization, the widget must display a list of all characters.
here is folder structure :
├───book
└───book.js
├───store
│ └───store.js
here is my store.js
window.Store = {
create: function() {
var self = {};
var props = {
name: 'string',
species: 'string',
picture: 'string',
description: 'string'
};
var listProps = ['name', 'species'];
var detailProps = ['name', 'species', 'picture', 'description'];
var characters = [
{
id: makeID(),
name: 'Ndiefi',
species: 'Wookie',
picture: 'store/img/ndiefi.png',
description: 'A legendary Wookiee warrior and Han Solo’s co-pilot aboard the Millennium Falcon, Chewbacca was part of a core group of Rebels who restored freedom to the galaxy. Known for his short temper and accuracy with a bowcaster, Chewie also has a big heart -- and is unwavering in his loyalty to his friends. He has stuck with Han through years of turmoil that have changed both the galaxy and their lives.',
_delay: 500
},
];
}
}
here is index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Character Book</title>
<!-- 3rd party vendor libraries -->
<link rel="stylesheet" href="vendor/font-awesome-4.6.3/css/font-awesome.min.css">
<script src="vendor/jquery-3.1.0.min.js"></script>
<script src="vendor/underscore-1.8.3.min.js"></script>
<!-- 1st party internal libraries -->
<script src="store/store.js"></script>
<script src="tests/start-test.js"></script>
<script src="tests/test-book.js"></script>
<!-- The source of the 'Book' widget -->
<link href="book/book.css" rel="stylesheet">
<script src="book/book.js"></script>
<script>
$(function() {
var frame = $('#test-frame');
var run = $('#test-run');
var results = $('#test-results');
var store = Store.create();
run.click(function() {
run.prop('disabled', true).text('Running Tests');
results.removeClass('test-pass test-fail').text('');
testBook(frame).then(
function success() {
run.prop('disabled', false).text('Run Tests');
results.addClass('test-pass').text('All tests passed');
},
function failure(err) {
run.prop('disabled', false).text('Run Tests');
results.addClass('test-fail').text('Test failed, see console');
}
);
});
Book.init(frame, store);
});
</script>
</head>
<body>
<button id="test-run">Run Tests</button>
<span id="test-results"></span>
<div id="test-frame">
</div>
</body>
</html>
here is what I have tried :
books.js
var data = JSON.parse(characters);
data.forEach(characters => {
console.log(characters.name)
});
so when I run the app in my browser I see the following error :
Uncaught ReferenceError: characters is not defined
what is wrong with my code ? any suggestion or help will be helpfull thanks
I am trying to load ejs templates in my express app. I set the 'view engine' to ejs and, passed an ejs template to the response.render. However,when I am navigating to localhost:8000, I am only seeing the include statements in literal form.
The template file:
index.ejs
{% include('commonheader') %}
<div id='mainbody' class='container-fluid'>
<nav>
{%- include('mainheader', {
navbar: navbar_options
}) %}
</nav>
</div>
{%- include('commonfooter', {
footer: sitemap
}) %}
commonheader.ejs
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<title><%= title %></title>
<!-- bootstrap -->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous">
<!-- bootstrap js -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
crossorigin="anonymous"></script>
<!-- Jquery -->
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
<!-- Custom stylesheets and js -->
<%- if(stylesheets){
if(typeof stylesheets == []){
Array.prototype.forEach(function(sheet){
%}<link rel='stylesheet' href= {%= sheet %}>{%
}, stylesheets);
}
else{
%}<link rel='stylesheet' href= {%= Array.prototype.shift.call(stylesheets) %}>{%;
}
}; %}
</head>
<body>
commonfooter.ejs
<footer>
<% if(footer){
for(let k in footer){
if(typeof footer[k] []){
Array.prototype.forEach.call(function(link){
%}<a href= {%= link['href'] %}>
<li>{%= link['name'] %}</li>
</a>{%
});
}
else{
%}<a href= {%= link['href'] %}>
<ul>{%= link['name'] %}</ul>{%
}
}
%}
</footer>
</body>
</html>
routes.js
const express = require('express');
const path = require('path');
const appinst = express();
const _template_dir = '/static';
const _root_addr = '127.0.0.1:8000';
// bind render engine to ejs
appinst.set('views', path.join(__dirname,'views'));
appinst.set('view engine', 'ejs');
appinst.get('/', function(request, response){
response.render('index', {
css_stylesheets: [
'css/index.css',
],
navbar_options: [
{
'href': _root_addr + '/',
'name': 'Home'
},
{
'href': _root_addr + '/create',
'name': 'Create'
},
{
'href': _root_addr + '/howto',
'name': 'How To'
}
],
sitemap: [
{
'href': _root_addr + '/',
'name': 'Home'
},
{
'href': _root_addr + '/aboutus',
'name': 'About Us'
},
{
'href': _root_addr + '/create',
'name': 'Create'
},
{
'href': _root_addr + '/howto',
'name': 'How To'
},
{
'href': _root_addr + '/contactus',
'name': 'Contact Us'
}
]
});
});
Browser Output:
{% include('commonheader') %}
{%- include('mainheader', { navbar: navbar_options }) %}
{%- include('commonfooter', { footer: sitemap }) %}
i think you mistyped the inclusion, should look like this:
<%- include('mainheader', { navbar: navbar_options }); %>
but from your code you're missing the opening and closing tag <%- %>
you're only using the %- and %
{%- include('mainheader', { navbar: navbar_options }) %}