How can we require a parameter in an ejs template such that ejs.render fails when the parameter is undefined? - ejs

I need to set the parameter so that if the parameter passed through to the template is undefined, the template rendering fails with an error.
Example template:
let template = "Hello <%=info.name%>, this is a test template.";
And when calling render, I send the following:
let data = {
info: {
name: "Bob"
}
};
let rendered_template = ejs.render(template, data);
This gives the following value for rendered_template:
Hello Bob, this is a test template.
However, if info.name is undefined, then the template still gets rendered (it will only fail if info itself is undefined, because it won't be able to read property name of undefined), and the result is the following:
Hello , this is a test template.
How can I set the info.name parameter to be mandatory, so that ejs.render fails if the value of info.name is undefined?

You could use the include function in conjunction with an if/else block:
<% if (info.name != undefined) { %>
<%- include 'someTemplate' %>
<% } %>
<% else { %>
<%- include 'someOtherTemplate' %>
<% } %>
Where someOtherTemplate is the error page you want to render when info.name is undefined.
Update
To send an error message with node.js, you can do something like this:
app.get('/someRoute', function(req, res) {
if (info.name) {
res.render('someTemplate', {info:info});
}
else {
res.status(403);
}
});

Related

Bootstrap-vue modal manipulate ok-disabled state in function

I've set the default OK Button in a Bootstrap-Vue Modal to disabled true and want to change it when inputing something in ab-form-input. Calling the function works but disabling ok-disabled not. Can't get access to the property. Seems to be a very basic question but in the component docs in bootstrap-vue there is only the infor that state can be changed (true-false) but not how to manipulate via script.
`
<template>
<b-modal
id="component-modal"
title="Add Component"
#ok="handleOk"
:ok-disabled="true"
>
<div class="container">
<b-row>
<b-col>Component: </b-col>
<b-col>
<b-form-input
v-model="component"
id="new-component"
required
#input="enableOK"
></b-form-input>
</b-col>
</b-row>
</div>
</b-modal>
</template>
<script>
import axios from 'axios';
import store from '../../store';
export default {
data() {
return {
count: 0,
};
},
methods: {
handleOk() {
this.handleSubmit();
},
handleSubmit() {
this.insertComponentClass(this.component, store.state.project);
delete this.component;
},
insertComponentClass(componentClass, pid) {
const path = `${store.state.apiURL}/componentclass/add`;
const payload = {
name: componentClass,
project_id: pid,
};
axios
.put(path, payload)
.then(() => {
this.$parent.getComponents();
})
.catch((error) => {
console.error(error);
});
},
enableOK() {
console.info('enable ok fired');
this.ok-disable = false; // doesnt wor, linter says "Invalid left-hand side in assignment expression"
},
},
};
</script>
`
There's a few things going on here that are incorrect.
You're binding the ok-disabled prop to a hardcoded value of true in your template. If you want that value to change, you'll need to bind it to a variable that you can update in your components <script>
For example, you can update the modal's :ok-disabled prop to:
:ok-disabled="okDisabled"
Then in your <script> data function, add it to the return object (defaulted to true):
data() {
return {
count: 0,
okDisabled: true,
}
}
Now the modal's :ok-disabled property is bound to that variable and we can change the value in the enableOk method like so:
this.okDisabled = false;
Note regarding the lint error, the name of the variable you're trying to assign to this.ok-disable is not a valid variable name. You can't use a dash (-) character for a Javascript variable name. You can rename it to the property we created earlier this.okDisabled

ReferenceError: " postIts.forEach(function(postit)" on list.ejs? postIts is not defined at eval (eval at compile

I need to loop through an object PostIts and display the "Id", " Title" with an ejs "forEach" Loop Am using sails.js "1.2.3" and mongodb on local host, but i get error
ReferenceError : postIts is not defined at eval (eval at compile ?
Here is the code on the PostItsController.js:
module.exports = {
list: function(req, res) {
// res.view('list');
PostIts.find({}).exec(function(err, postIts) {
if (err) {
res.send(500, { error: 'Database Error' });
}
res.view('list', { postIts: postIts });
});
}
};
And here is the code on list.ejs:
<tbody>
<% postIts.forEach(function(postit){ %>
<tr>
<td>
<%= postit.id %>
</td>
<td>
<%= postit.title %>
</td>
<td></td>
</tr>
<% }) %>
</tbody>
I should get the value of the ID and title displayed on the list.ejs page in a table, but instead I get an error that the postIts object is not defined.
First of all your route '/postIts/list': { view: 'list' }, should point to an action (since it has backend logic) not a view, so in your case "/postIts/list": "PostItsController.list", but if you're using actions2 things would be simpler
Secondly you don't need to tell your users that you have a database error error: "Database Error"
Using Actions2
sails generate action post/list
In your config/route.js
'POST /api/v1/post/list': { action: 'post/list' },
In your action
module.exports = {
friendlyName: "List Posts",
description: "List all post in our site",
inputs: {},
exits: {
success: {
description: "The path to your template file",
viewTemplatePath: "list"
}
},
fn: async function(inputs) {
var posts = await Post.find();
// All done.
return { postIts: posts };
}
};
postit works
An Boohoo! it works
https://sailsjs.com/documentation/concepts/actions-and-controllers/routing-to-actions
If you're sure that res.view('list', { postIts: postIts }); is actually sending the correct data you can use _.each(postIts, cb()) ... instead
For some reason the postIts object didnt save the data from the post req I made instead it just recalled what I posted. and I used the '_.each(postIts, function (postit)' and it finally worked.
to me its like a magic happened hahaha but yeah I learned from it.
thanks #Navicstein Rotciv for the quick replies.

How to use dynamic page titles in sails.js >v1.0?

For the last few days I was looking for a viable solution in order to optimize html page titles <title>SOME_TITLE</title> within sails.js layout files, like layout.ejs, that by default use a static page title.
Obviously, it would be way better to have dynamic page titles, e.g. Dashboard, Shopping Cart, etc...
Other people were looking for this answer before and got answers for prior sails versions in Solution 1, Solution 2 and Solution 3.
Unfortunately, none of them seem to be appropriate for the latest version of sails.js (as of this post).
Solution 1 was leading in the right direction and suggested what I was looking for. But you had to define a title for every controller and pass it into the view. Otherwise you will get
title is not defined at eval
So how to define a local variable that is accessible in each controller/view by default?
So one working complete solution for the current sails.js version is the following:
In your layout.ejs file define a dynamic page title like this
<head>
<title>
<%= title %>
</title>
...
</head>
...
Create a new custom hook, e.g. api/hooks/dynamic-page-title/index.js
module.exports = function dynamicPageTitleHook(sails) {
return {
routes: {
/**
* Runs before every matching route.
*
* #param {Ref} req
* #param {Ref} res
* #param {Function} next
*/
before: {
'/*': {
skipAssets: true,
fn: async function(req, res, next){
// add page title variable to each response
if (req.method === 'GET') {
if (res.locals.title === undefined) {
res.locals.title = 'plusX';
}
}
return next();
}
}
}
}
};
};
Now overwrite the page title in every controller that should use a custom page title, e.g. view-login.ejs
module.exports = {
friendlyName: 'View login',
description: 'Display "Login" page.',
exits: {
success: {
viewTemplatePath: 'pages/entrance/login',
},
redirect: {
description: 'The requesting user is already logged in.',
responseType: 'redirect'
}
},
fn: async function (inputs, exits) {
if (this.req.me) {
throw {redirect: '/'};
}
return exits.success({title: 'Login'});
}
};
module.exports = {
friendlyName: 'View homepage or redirect',
description: 'Display or redirect to the appropriate homepage, depending on login status.',
exits: {
success: {
statusCode: 200,
description: 'Requesting user is a guest, so show the public landing page.',
viewTemplatePath: 'pages/homepage'
},
redirect: {
responseType: 'redirect',
description: 'Requesting user is logged in, so redirect to the internal welcome page.'
},
},
fn: async function () {
if (this.req.me) {
throw {redirect:'/welcome'};
}
return {title: 'Home page'};
}
};
e.g: return (title: 'Home page')
I use version 1.4 of sails
I have add to the file layout.ejs the following code
<% if (typeof pagetitle=="undefined"){%>
<title>write your default title</title>
<% }else{%>
<title><%= pagetitle %></title>
<%}%>
<% if (typeof pagemetadescription=="undefined"){%>
<mеtа nаmе="dеѕсrірtіоn" соntеnt="write your default metadescription"></mеtа>
<% }else{%>
<mеtа nаmе="dеѕсrірtіоn" соntеnt="<%= pagemetadescription %>"></mеtа>
<%}%>
If in controller, i return variable pagetitle or pagedescription, they will be add to layout. Otherwise, the default value will be print.

Mongodb return an Empty array

I am trying to make a range query and show the data in my ejs view
EJS View "historicos.ejs"
<h1>historicos</h1>
<form action="/historicos/buscar">
<input type="text" name='inicio' id='inicio'></li>
<input type="text" name='final' id='final'></li>
<br>
<button type="submit">Buscar</button>
</form>
<% if(typeof his !== 'undefined'){
his.forEach(function(dati){%>
<%= dati.temp %>
<%= dati.hum %>
<%= dati.date %>
<br/>
<%});
}; %>
I am using a controller with 2 methods, 1 for render the page and one to manage the query.
Controller "grafi.js"
var Si = require('../models/sis');
exports.getPagehis = function(req, res) {
if (req.user) return res.redirect('/');
res.render('historicos');
};
exports.getHis= function(req, res, next) {
ini = req.body.inicio;
fin = req.body.final;
console.log(ini)
console.log(fin)
Si.find({"date": {"$gte":ini, "$lt":fin}},function(err, his) {
console.log(his);
if(err) return next(err);
res.render('historicos', {
his:his
});
});
};
and this is my router file
router.get('/historicos', hiController.getPagehis);
router.get('/historicos/buscar', hiController.getHis);
if I write manually ini and fin to make the query(using this format YYYY-MM-DDThh:mm), I mean without the req.body.inicial and req.body.final, it work well but when I request the information from the view I got this fields undifined.
what can i do to solve this?
the problem was form and the request in general adding method="get" in the form and update the controller with:
var Url = require('url');
...
queryparams = Url.parse(req.url,true).query;
ini = queryparams.ini;
fi = queryparams.fi;
... make the query to mongo db
with this code is possible to get the values in the input files passed in the url

JSON object parsing error using jQuery Form Plugin

Environment: JQuery Form Plugin, jQuery 1.7.1, Zend Framework 1.11.11.
Cannot figure out why jQuery won't parse my json object if I specify an url other than a php file.
The form is as follows:
<form id="imageform" enctype="multipart/form-data">
Upload your image <input type="file" name="photoimg" id="photoimg" />
<input type="submit" id ="button" value="Send" />
</form>
The javascript triggering the ajax request is:
<script type="text/javascript" >
$(document).ready(function() {
var options = {
type: "POST",
url: "<?php $this->baseURL();?>/contact/upload",
dataType: 'json',
success: function(result) {
console.log(result);
},
error: function(ob,errStr) {
console.log(ob);
alert('There was an error processing your request. Please try again. '+errStr);
}
};
$("#imageform").ajaxForm(options);
});
</script>
The code in my zend controller is:
class ContactController extends BaseController {
public function init() {
/* Initialize action controller here */
}
public function indexAction() {
}
public function uploadAction() {
if (isset($_POST) and $_SERVER['REQUEST_METHOD'] == "POST") {
$image = $_FILES['photoimg']['tmp_name'];
$im = new imagick($image);
$im->pingImage($image);
$im->readImage($image);
$im->thumbnailImage(75, null);
$im->writeImage('userImages/test/test_thumb.jpg');
$im->destroy();
echo json_encode(array("status" => "success", "message" => "posted successfully"));
}
else
echo json_encode(array("status" => "fail", "message" => "not posted successfully"));
}
}
When I create an upload.php file with the above code, and modify the url from the ajax request to
url: "upload.php",
i don't run into that parsing error, and the json object is properly returned. Any help to figure out what I'm doing wrong would be greatly appreciated! Thanks.
You need either to disable layouts, or using an action helper such as ContextSwitch or AjaxContext (even better).
First option:
$this->_helper->viewRenderer->setNoRender(true);
$this->_helper->layout->disableLayout();
And for the second option, using AjaxContext, you should add in your _init() method:
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('upload', 'json')
->initContext();
This will disable automatically disable layouts and send a json header response.
So, instead of your two json_encode lines, you should write:
$this->status = "success";
$this->message = "posted successfully";
and
$this->status = "fail";
$this->message = "not posted successfully";
In order to set what to send back to the client, you simply have to assign whatever content you want into view variables, and these variables will be automatically convert to json (through Zend_Json).
Also, in order to tell your controller which action should be triggered, you need to add /format/json at the end of your URL in your jQuery script as follow:
url: "<?php $this->baseURL();?>/contact/upload/format/json",
More information about AjaxContext in the manual.
Is the Content-type header being properly set as "application/json" when returning your JSON?