I'm using a requirejs plugin to define "tmpl!" loader (not a jquery template, but a lodash template. The problem is that the text! loader is adding a ";" at the end of the template. This is being rendered and is breaking everything.
(function(global){
"use strict";
define({
load : function(name, require, load, config) {
var deps = [];
deps.push('text!' + name);
deps.push('underscore');
require(deps, function(source, _) {
var template = _.template(source);
load(template);
});
}
});
})(this);
How can I stop text! from adding a semi-colon? Or: is there a better way to do this?
Taking the questions in reverse order:
is there a better way to do this?
It seems there is an existing implementation of this, and you might want to consider using it rather than writing your own. Although the simple case is a small amount of code, there are a bunch of r.js optimizer-related things you might eventually need.
But regarding your implementation logic, I noticed that this similar project for Handlebars does not use the text! plugin but instead does its own XHR in the load() method. This is not explained, but he gives some guidance for adapting it to other templating languages. Note: the link came from this question where there is some other good discussion of the approach.
How can I stop text! from adding a semi-colon?
I tried your plug-in and did not get any added semicolons. Perhaps you could post more of the sample project and templates? Below is mine, with everything in one flat folder for simplicity:
require.js: latest from RequireJS site
domReady.js: latest from RequireJS site
text.js: latest from RequireJS site
lodash.js: latest from lodash site
tmpl.js: your example loader from the question
index.html:
<!DOCTYPE html>
<html>
<head>
<script src='require.js'></script>
<script>
requirejs.config({
map: {
'*': { 'underscore': 'lodash' }
}
});
require( [ 'underscore', 'tmpl!friend-template.htm', 'domReady!' ]
, function( _, friendTemplate ){
var friendsData = [{ name: 'Bob', age: 35 }, { name: 'Fred', age: 38 }];
document.body.innerHTML = friendTemplate( {friends: friendsData});
});
</script>
</head>
<body>
<!-- To be populated dynamically. -->
</body>
</html>
friend-template.htm:
<ul>
<% _.forEach(friends, function(friend) { %>
<li>
<span><%- friend.name %></span>
<span>( Age: <span class="value"><%- friend.age %></span> )</span>
</li>
<% }); %>
</ul>
I've created a loader specifically for Lo-Dash which you can see here:
https://gist.github.com/tbranyen/6821045
Note: I have no unit tests or assurances this free of bugs, but from my initial testing it appears to work fantastic.
This is better in a number of ways than requirejs-tpl which bakes in it's own implementation which is not exposed. It also requires a file extension and hardcoded path. Both of these are configurable in my code.
Edit: I've since released a project called lodash-template-loader which has tests. https://github.com/tbranyen/lodash-template-loader
Related
got this code from preact's site, and try to make it work without babel building process, but failed, anybody knows if this is possible? Thanks,
http://jsfiddle.net/e281k4wz/117/
'use strict';
const { Component, h, render } = window.preact;
render((
<div id="foo">
<span>Hello, world!</span>
<button onClick={ e => alert("hi!") }>Click Me</button>
</div>
), document.body);
Yes. You have to include babel before your jsx code and use the script as type="text/babel" see the following example with react
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/#babel/standalone/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/babel">
class App extends React.Component {
render() {
return (
<div className="app-content">
<h1>Hello from React</h1>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'));
</script>
</body>
</html>
You cannot directly use the JSX into the JavaScript as it's a invalid syntax.
For running the preact into the client you have to either transpile the jsx code into valid javascript or use the helper method (Component , h , render) provided by preact.
HTML
<h1>Render by Preact client library using h and render function</h1>
<div id="preact">
</div>
JavaScript
var Component = window.preact.Component,
h = window.preact.h,
render = window.preact.render;
var PreactApp = function (props){
return h('h1',
{className: ''},
'Hello from Preact world!');
}
render(PreactApp(),document.getElementById("preact"));
Here in JS if you see h ( converting jsx to vdom ) and render (converting vdom to html ) function actually do the magic. Read more about from the official documentation - https://preactjs.com/guide/api-reference
Working example - https://jsfiddle.net/97125m3z/2/
Technically it is possible by using the HTM package, as long as you're targeting recent browsers that understand template strings. See https://github.com/developit/htm for details.
However, this will render slower than simply creating the components using h() as it is a whole heap of string parsing. It also makes it difficult to use syntax highlighting in your IDE, which makes debugging frustrating.
I used HTM when I was first getting used to using Preact without a build step, but very quickly replaced it with manually creating the components and eliminated the JSX.
You get a better understanding of how everything fits together if you don't use the JSX abstraction. Babel compiles it down into createElement calls anyway.
Actually, I'm having trouble adding javascript code into my rails application.
I tried putting the import.js in "app/assets/javascripts" as well and it didn't work either.
I also added, //= require import at the end of application.js file but still not working.As a result the whole application got stucked.
index.html.erb
TEST
<div id = "test">
<h2>Import Statements</h2>
<%= form_tag import_samples_path, multipart: true do %>
<%= file_field_tag :file %>
<%= submit_tag "Import" %>
<% end %>
</div>
sample.coffee
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
$( document ).ready(function() {
$("div#test").hide();
$("a").click(function(event) {
event.preventDefault();
$("div#test").toggle();
});
});
application.js
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require bootstrap-sprockets
//= require nicetitle
Thanks in advance.
A couple of things here:
First off - you need to have a //= require_tree . inside of your application.js file. What this does is automatically requires all of the files inside of your javascripts directory.
Next, (and I'm not entirely sure that this is best practice) the way that I call javascript inside of a html.erb file is inside of a <script> tag. I'll put an example of my code below. I only very recently figured out how to call JS from inside of html in rails, so like I said this is probably not best practice, but this is how I did it.
<script language="javascript" type="text/javascript">
var counts = ['Count']
var dates = ['x']
<% #chart.datasource.datapoints.each do |c| %>
dates.push( "<%= c.date %>" )
counts.push( <%= c.count %> )
<% end %>
chart(counts, dates);
</script>
So I actually put it inside of a script tag like you saw. Hopefully this helps.
I don't know why but my layout is rendered two times.
Here is my index.html:
<head>
<title>title</title>
</head>
<body>
{{>layout}}
</body>
Here is my layout:
<template name="layout">
{{#if canShow}}
{{>Template.dynamic template=content}}
{{else}}
{{> loginButtons}}
{{/if}}
</template>
So here without route my template is display just one time.
Here is my route:
FlowRouter.route('/', {
action() {
BlazeLayout.render("layout", {
content: "home"
});
}
});
But with this route my template is display a second time.
This is my helpers, I think there is nothing to do with this problem but we never know.
Template.home.onCreated(function() {
this.autorun(() => {
this.subscribe('post');
});
});
Template.layout.helpers({
canShow() {
return !!Meteor.user();
}
});
Template.home.helpers({
cats() {
return Posts.find({});
}
});
you don't need to render layout in the body.
The router will take care of the rendering.
so, just have
<body>
</body>
or don't even have it at all.
Edit: Thanks to Keith, I have a better understanding of my problem. Here is his comment:
one thing to keep in mind, all the html you write in meteor isn't kept as html. It all gets converted to javascript. Things like index.html do not get pushed to the browsesr. Meteor just takes all the html you write converts it to javascript and renders what it needs to based on what your code says. This is how it knows todynamically change and rerender html
For things like changing title of the head or add meta etc, we can do it directely in the javascript.
ex: Meteor - Setting the document title
Hi I'm new to node and I'm trying to make a simple blog.
I want to route /pages/:post to search a database for "post" and return an html template file that I can use as a partial.
var posts = {
'myarticle': {
template: partial1.html
}
};
var findPost = function (post, callback) {
if (!posts[post])
return callback(new Error(
'No post matching '
+ post
)
);
return callback(null, posts[post]);
};
app.get('/pages/:post', function(request, response) {
var post = request.params.post;
findPost(post, function(error, post) {
if (error) return;
return response.render('posttemplate', post);
});
});
and posttemplate is a template file like ejs (i'm not comfortable with Jade as of yet) that looks like
<html>
<% include ../partials/header %>
<body>
<% include /thereturnedpost %>
</body>
</html>
Is this possible? I've looked through documentation/tutorials but none of them are clear.
I'l answer with codes examples from my current project
<body>
<%- body %>
<script type="text/javascript" src="/vendors.js"></script>
<script type="text/javascript" src="/main.js"></script>
</body>
and
res.render('index', {
body: content
});
So your example is almost correct. After fetching the data from the database you send it to render function (in my case I render content ).
It is for the case when you keep in the db html string.
Also I can recommend you to use markdown (e.g. markdown-js) for the blog posts. It may be simpler to write and edit well formatted content, and less information to keep (comparing to html).
As per your coding, your blog post contents are static and are in template htmls.
If you get the data from db, you should modify your code such that the template file is with the HTML markup/ejs variables and send the data values separately.
This can be accomplished through ejs.renderFile method...https://www.npmjs.com/package/ejs2
Hope it will help you...
I have a pretty large object that I need to pass to a function in a client script. I have tried using JSON.stringify, but have run into a few issues with this approach - mostly performance related. Is it possible to do something like this in ejs?
app.get('/load', function(req, res) {
var data = {
layout:'interview/load',
locals: {
interview: '',
data: someLargeObj
}
};
res.render('load', data);
});
And in my client script, I would pass this object to a function like so
<script type="text/javascript">
load(<%- data %>); // load is a function in a client script
</script>
When I try this I get either
<script type="text/javascript">
load();
</script>
or
<script type="text/javascript">
load([Object object]);
</script>
In Node.js:
res.render('mytemplate', {data: myobject});
In EJS:
<script type='text/javascript'>
var rows =<%-JSON.stringify(data)%>
</script>
SECURITY NOTE : Don't use this to render an object with user-supplied data. It would be possible for someone like Little Bobby Tables to include a substring that breaks the JSON string and starts an executable tag or somesuch. For instance, in Node.js this looks pretty innocent...
var data = {"color": client.favorite_color}
but could result in a client-provided script being executed in user's browsers if they enter a color such as:
"titanium </script><script>alert('pwnd!')</script> oxide"
If you need to include user-provided content, please see https://stackoverflow.com/a/37920555/645715 for a better answer using Base64 encoding
That is the expected behavior. Your template engine is trying to create a string from your object which leads to [Object object]. If you really want to pass data like that I think you did the correct thing by stringifying the object.
If you are using templating, then it would be much better to get the values in the template, for example whether user is signed in or not. You can get the send local data using
<script>
window.user = <%- JSON.stringify(user || null) %>
</script>
From the server side code, you are sending user data.
res.render('profile', {
user: user.loggedin,
title: "Title of page"
});
Think there's a much better way when passing an object to the ejs , you dont have to deal with JSON.stringfy and JSON.parse methods, those are a little bit tricky and confusing. Instead you can use the for in loop to travel the keys of your objects, for example:
if you have an object like such hierarchy
{
"index": {
"url": "/",
"path_to_layout": "views/index.ejs",
"path_to_data": [
"data/global.json",
{
"data/meta.json": "default"
}
]
},
"home": {
"url": "/home",
"path_to_layout": "views/home/index.ejs",
"path_to_data": [
"data/global.json",
{
"data/meta.json": "home"
}
]
},
"about": {
"url": "/about",
"path_to_layout": "views/default.ejs",
"path_to_data": [
"data/global.json",
{
"data/meta.json": "about"
}
]
}
}
On the EJS side you can loop yourObject like this;
<% if ( locals.yourObject) { %>
<% for(key in yourObject) { %>
<% if(yourObject.hasOwnProperty(key)) { %>
<div> <a class="pagelist" href="<%= yourObject[key]['subkey'] %>"><%= key %></a></div>
<% } %>
<% } %>
<% } %>
For this example [key] can take 'index','home' and 'about' values and subkey can be any of it's children such as 'url','path_to_layout','path_to_data'
What you have is a result like this
[{'re': 'tg'}]
You actually need to loop it. See javascript while loop https://www.w3schools.com/js/js_loop_while.asp
Then, render it in your front end with ejs... i can't help on that, i use hbs