Nodejs use method in view - node.js

For example,In my Nodejs app,I have a router:
exports.test=function(req,res){
res.render('./admin/test.jade',{html:[a,b,c]);
}
And I have Underscore.js
In my view test.jade:
-var _und=require('Underscore.js')
....
div
-_und.each(html,function(m))
span m
....
But I got error.This shows that,the Underscore.js is just be used as a server-side method,how can I use a server-side method in view?

You don't need to require underscore from a view. To view you should send just data (it means that in idea case you should not use underscore there at all). But if you would like, you can still send underscore like a function to view:
exports.test = function(req,res) {
res.render('./admin/test.jade',{ html: [a,b,c], _ : require("underscore") });
};
or like this:
exports.test = function(req,res) {
var underscore = require("underscore");
res.render('./admin/test.jade', { html : [a,b,c], _ : underscore });
}
After in your view you can access to that like this:
div
-_und.each(html,function(m))
span m
You can get inspired from my nodejs github markdown project (http://bit.ly/1aOAG35). There is used underscore for layouting and I'm using it as well in templates:
{{# onlyblogs.forEach(function(current){ }}
<li>
{{ current.title }}
{{# if (current.description){ }}
<span>{{ current.description }}</span>
{{# } }}
<span>{{ current.category }}</span> in <date>{{ current.date }}</date>.
</li>
{{# }); }}
Hope that it helped.

Related

Twig include with rerender

I want to include some template and append on button click (by js), and I need each included template to have a unique id.
Here is the logic where I appending the templates:
<button type="submit" id="addTranslationFields">Add translations</button>
// and js
$('#addTranslationFields').on('click', function (event) {
event.preventDefault();
event.stopPropagation();
let part = `{% include 'translationPart.twig' with {'languages': languages,}%}`;
$('.table tbody').append(part);
});
Here is the how I generate uuid in the translationPart.twig
{% set uuid = uuid() %}
{{ uuid }}
The issue is that UUID is the same for all of the created templates. I understand why it's happening, it's b-z twig generated server-side and at the moment of generation it sees only one include. But is there some option to rerender included template for each new included copy? Or maybe some other way to set different UUIDs for each of the included templates.
Updated
uuid() is a custom twig function
$twig->addFunction(
new TwigFunction(
'uuid',
static function(): string {
return Uuid::uuid4()->toString();
}
)
);
You can achieve this via ajax calls, or string replacement.
String replacement
Twig template (translationPart.twig)
{% set uuid = '#_SOME_STRING_TO_REPLACE_#' %}
{{ uuid }}
Javascript
<button type="submit" id="addTranslationFields">Add translations</button>
// and js
$('#addTranslationFields').on('click', function (event) {
event.preventDefault();
event.stopPropagation();
let generatedUuid = generateUuidByJavascript();
let part = `{% include 'translationPart.twig' with {'languages': languages,}%}`.replace('#_SOME_STRING_TO_REPLACE_#', generatedUuid);
$('.table tbody').append(part);
});
Uuidjs can be used for generating uuid.

LitElement use of template with binding

I was wondering how to make LitElement work similar to Polymer 2/3 templatizer, i.e. grab template from light dom (childElement), templetize it and stamp it. It used to be possible and was used in elements such as dom-repeat etc, however with LitElement and its internal working with tagged string templates I do not see how to make an element accept a template to use internally, but the template being provided by the user of the shipped element (i.e. same as dom-repeat used to allow that).
I am aware of how to do it when writing the code, I just want to allow the consumer of my custom element to be able to provide the template and its bindings to work and not to subclass my element but instead use the simpler and already well known html composition from polymer2/3
You can't really do this with just lit-html, as everything is built on JS template strings. You might be interested in Stampino, which is built on lit-html. It's in pre-release as of this writing.
<template id="root">
<h1>{{ title }}</h1>
<ul>
<template type="repeat" repeat="{{ items }}">
<li>{{ toUpperCase(item) }}</li>
</template>
</ul>
</template>
<output></output>
<script type="module">
import { render } from 'stampino';
render(
document.getElementById('root'),
document.querySelector('output'),
{
letters: ['a', 'b', 'c'],
title: 'Hello World',
toUpperCase(string) {
return string.toUpperCase();
}
}
);
</script>
That would render the following to the <output> element:
<h1>Hello World</h1>
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
</ul>
If you're already writing HTML inside a lit-html template, however, a pattern that may fit your use is so-called "render props". Here's a simplified example:
html`
<list-renderer
.items="${[...items]}"
.template="${item => html`
<list-item>${item}</list-item>
`}"></list-renderer>
`;
in which,
class ListRenderer extends LitHTML {
render() {
return html`
<ul>
${this.items.map(item => this.template(item))}
</ul>
`;
}
}

Symfony 4 How to add an attribute to a twig using jquery?

I'm trying to do a form with symfony 4. It works fine. But I have a problem.
I have a field to write a comment. By default, it's not required.
However, I would like to change this using jquery.
This is what I tried to do.
Here, it's my twig:
<div class="information" id="informationForm">
{{ form_row(recordForm.category) }}
{{ form_row(recordForm.information) }}
{{ form_label(recordForm.comment) }}
{{ form_widget(recordForm.comment, {'attr': {'class': 'comment'}}) }}
{{ form_errors(recordForm.comment) }}
<button id="add_information_button" class="btn btn-primary">Ajouter un renseignement</button>
<button id="count_div" class="btn btn-primary">Compter</button>
<button class="remove_information_button btn btn-primary">Supprimer un renseignement</button>
</div>
Here it's the javascript:
$('.information')
.on("change", ".record_to_information_form_information", function (event) {
event.preventDefault();
var $commentState = $(this).find('option:selected').data('comment')
//Test: to know if i received the attribute
console.log($commentState)
if($commentState===false){
//the field isn't required
// {{ form_widget(recordForm.comment, {'attr': {'required': 'false'}}) }}
}else{
//the field is required
// {{ form_widget(recordForm.comment, {'attr': {'required': 'true'}}) }}
}
})
;
Do you have any suggestions?
You can toggle required property value from your jQuery code.
I assume that data-comment attribute has type boolean and it's always set, so your toggle statement can look as follows:
$('.information')
.on("change", ".record_to_information_form_information", function (event) {
event.preventDefault();
var $commentState = $(this).find('option:selected').data('comment');
//Test: to know if i received the attribute
console.log($commentState);
$('.comment').prop('required', $commentState);
});
If you need to do something else in your if-else statement, you can just leave your condition as you provided in sample:
if ($commentState === false) {
//the field isn't required
$('.comment').prop('required', false);
} else {
//the field is required
$('.comment').prop('required', true);
}

How do I use req.flash() with nunjucks?

I am using connect-flash to pass the flash message. In my controller, I am using the following code if (!req.user) {
req.flash("error_msg", "User not found !!");
return res.redirect(307, '/');
}
In my view, I tried
{{ error_message }}
{{ req.flash('error_message') }}
{{ req.flash.get('error_message') }}
But none of it works. What's the current syntax to parse the flash message in nunjucks ?
First of all you have to install "express-flash" and put below code in app.js
app.js
const flash = require('express-flash');
In Your Controller put below code when you want to pass message
req.flash('error_msg', "User not found !!");
return res.redirect(307, '/');
Put below code in your view file where you want to display message
<% if (typeof messages.error_msg !='undefined') { %>
<p class="error"><%= messages.error_msg %></p>
<% } %>
For anyone facing the same problem you can access the variable using {{ req.session.flash.error_msg }}
If you are using express js and nunjucks as template this is what I have done
in app.js
const flash = require('express-flash');
app.use(flash());
in Routes/controller code
try {
await User.deleteOne({_id:req.params._id}).exec()
req.flash("success_msg", "User deleted");
return res.redirect('/admin/users')
}
in Layout or view file
{% if messages.success_msg %}
<div class="alert alert-success" role="alert">
{{ messages.success_msg }}
</div>
{% endif %}
With connect-flash package, you cannot directly use req.flash in template engine. You need to add a middleware that adds the flash message to the res.locals which can be accessed in template rendering.
Here is a short code snippet.
// this part should be before all the request resolver.
// adding flash function to response locals
app.use((req,res,next)=>{
res.locals.flash = (arg) => { return req.flash(arg) };
next();
});
// request resolver
app.get("/",(req,res)=>{
req.flash("info","show me");
res.render("index.njk",{});
});
app.listen(8080,()=>{...})
In nunjucks file:
<h3>{{ flash("info") }}</h3>

ejs 2 custom delimiter

EJS2 can only do character to be use with angle brackets for open/close:
ejs.delimiter = '$';
ejs.render('<$= users.join(" | "); $>', {users: users});
I would like to use {{ }} instead of <% %>, previous version will allow this esj.open = '{{' and esj.close = '}}'.
Any help?
EJS has been updated & changed maintainers, so the main site is found here: https://ejs.co/
and the Github is here: https://github.com/mde/ejs
Unlike previous versions of EJS, you can't use completely custom delimiters now - you can use 'partial' custom delimiters - the first set of brackets aren't optional, but the following character is. To set up a custom delimiter you can do the following:
// app.js
const ejs = require('ejs');
ejs.delimiter = '?';
app.get('/', (req, res) => {
res.render('index', {
myVariable: 'Hey!'
});
});
// index.ejs
<div>
<p>
<?=myVariable ?>
</p>
</div>
// index.html (rendered output)
<div>
<p>
Hey!
</p>
</div>
You can add a complete options object and other things, but hopefully that gets you started if you want to change the default delimiters.
Documentation states that custom delimiters are supported:
https://github.com/tj/ejs#custom-delimiters
This isn't possible without modifying the module's source code.
My solution to using custom delimiters is be doing a string replace on the template
const template = fs.readFileSync(path.join(__dirname, './template.html'), 'utf8').replace('{{', '<%').replace('}}', '%>')
const render = ejs.compile(template)
This allows me to declare my template like this:
{{ if (someVar) { }}
{{= someVar }}
{{ } }}

Resources