I'm becoming a huge fan of CoffeeKup, but I'm wondering how I can use literal HTML in such a template? For example when I just want to copy-paste some existing, non-CoffeeKup markup.
You can add arbitrary text with the text function:
text '<p>foo</p>'
For multiline strings, CoffeeScript's heredocs are a pleasure:
text '''
<table>
<tr>
<td>Foo</td>
</tr>
</table>
'''
Just make sure you have autoescape set to false (the default value).
Have you tried using this tool too for converting your markup instead of just inlining in?
https://github.com/brandonbloom/html2coffeekup
It's linked from the main github page of coffeekup. If it handles your old markup it would be a more elegant solution.
Related
(First allow me to say that I'm just beginning to learn Node-RED concepts; I went through some beginners' guides at nodered.org, and now am trying to extend what I learned so far).
I'm trying to build a flow that starts with a simple JSON tree like
[{"position":"1", "title":"element #1"},
{"position":"2", "title":"element #2"},
{"position":"3", "title":"element #3"}]
To build that treee I use a template node, property is set to msg.payload.
The number of array elements (in theory) is dynamic. To make sure that this tree is true JSON I added a JSON node converting from String to JSON object.
Next I wish to parse that object into a dynamic html table. For this I used a JS function node that's looping through the object and embedding its elements into the according html elements like this:
var return="";
for(var i=0;i<=msg.payload.length-1;i++){
var row=msg.payload[i];
if(row){
return+="<tr>";
return+="<td>"+row.position+"</td>";
return+="<td>"+row.title+"</td>";
return+="</tr>";
}else{
return+="no object at index "+i.toString();
}
}
msg.payload=return;
return msg;
The output of the function then should be passed into a 2nd template like this:
<html>
<head></head>
<body>
<table border="1">
<tr>
<td>#</td>
<td>Title</td>
</tr>
{{ payload }}
</table>
</body>
</html>
I would have expected that the function's result is inserted into the static table of my template, and that happens indeed but not the way I hoped: somehow the html elements that got created by my function are not recognized as what they shoud be; instead I see that they are rendered as
<tr><td>1</td><
instead of
<tr><td>1</td>
etc.
Result is that the browser does not recognize those elements and prints them together with their contents outside my static table
Questions:
what do I need to do so that my 2nd template recognizes my computed string as a set of html elements?
or is this probably a concept not suitable for my purpose?
I'm assuming you are using handelbars for your templating engine. In that case use:
{{{ payload }}}
Instead of
{{ payload }}
However a more elegant approach would be this:
<html>
<head></head>
<body>
<table border="1">
<tr>
<td>#</td>
<td>Title</td>
</tr>
{{#each payload}}
<tr><td>{{this.position}}</td><td>{{this.title}}</td></tr>
{{/each}}
</table>
</body>
</html>
then just
return msg.payload
again thanks to #als9xd for pointing me into the right direction; his 2nd idea indeed sounds much more elegant but first I couldn't get it to work. After some trial-and-error and looking up documentation for the template node I finally came up with this: removed the function node from my original question and then altered the 2nd template to this code:
<html>
<head></head>
<body>
<table border="1">
<tr>
<td>#</td>
<td>Title</td>
</tr>
{{#payload}}
<tr>
<td>{{position}}</td>
<td>{{title}}</td>
</tr>
{{/payload}}
</table>
</body>
</html>
Difference to #als9xd's example is that I replaced {{#each payload}} with a simple {{#payload}}, plus omitted this when referencing the object keys.
Could this be due to different Node-RED versions?
Anyways this is starting to be much fun!
Consider the following markup:
<div hidden id="table-template">
<table>
<tbody>
<slot></slot>
</tbody>
</table>
</div>
<div hidden id="table-row-template">
<tr>
<td>
Some Content
</td>
</tr>
</div>
I would like to use 'table-template' and 'table-row-template' as re-usable components in my script.
(clone them and append them on demand)
but as the page loads the browser parses the markup and mutates it (taking 'slot' element and insert it before the 'table' element, and stripping 'td' and 'tr' tags).
This is reasonable (not valid HTML of course), but is there any way I can prevent the browser from parsing those elements?
So far I have tried:
using hidden elements,
wrapping with 'pre'/'code' tags,
but none seem to work.
You can try using <script type="text/template"></script>
<script id="mytemplate" type="text/template">
...your table's html...
</script>
Then:
<script>
alert($('#mytemplate').html());
</script>
Many libraries use this method, handlebar.js for example.
The <template> element may gain compatibility with more browser versions: http://caniuse.com/#feat=template
Use a fictional tag that the browser wouldn't recognise. You can still target it with Javascript and read it's text content but the browser won't parse it.
Say <template id="the-template">Foo bar</template>.
But really the best way to re-use html snippets it to create them in Javascript without polluting the DOM.
e.g
var elToReuse = document.createElement('div').innerHTML('<h1>Lets have title here</h1>');
// Let's do some things to the elToReuse
var anotherVersion = elToReuse.querySelector('h1').innerText('My another title');
// Now it's the time to append to the DOM
document.body.appendChild(anotherVersion);
So I have researched a bit about my problem, and this is what i figured out -
the 'tbody' element accpets only 'tr' elements as children.
so browsers will 'fix' the markup while parsing it one way or the other.
using template tags as vassiliskrikonis suggested will not work for the 'table-template' but will fix the 'table-row-template' issue,
using script tag as #Mihaly_KR suggested will work for both, but when accessing the template you will get a plain string to work with (injecting this string into the DOM will make the browser parse it and 'fix' it once again...)
The workaround I have found is to use other tag as a placeholder for my content.
one way is using a comment e.g.
but accessing this comment element requires a use of treeWalker or nodeIterator (which are much less performant then querySelector or getElementsByTagName)
other way is using a script tag as a placeholder.
browsers will not change the markup, and it can be accessed later using querySelector or getElementsByTagName.
so my refactored code looks like this:
<template id="table-template">
<table>
<tbody>
<script type="slot"></script>
</tbody>
</table>
</template>
<template id="table-row-template">
<tr>
<td>
Some Content
</td>
</tr>
</template>
This is a branch off from this question: Handlebars.JS (w/ Dashbars) parse error "expecting open_endblock got inverse" (There's also a codepen therein.) I posted this there because I thought the problems were related, maybe (since {{else}} can be used with if's or each's,) but that turned out not to be the case.
Specifically:
I'm also having the problem of my outermost {{#each}} looping in such a way that only the last record returned is being output through the template. Everything logs in {{log this}} after that opening {{#each}}, but it's not even hiding in the HTML output somewhere.
So my table SHOULD have 4 rows, and objects 0 through 3 log to the console, but only the fourth item, item 3, is added to the table. Inner each's work as expected, as do any and all other iterator functions; I'm not sure why it's JUST the outer one that's failing. The JSON from which my array of objects is created validates in every single linter I've used, as does my JavaScript. Atom is supposed to have a handlebars linter, but it doesn't seem to actually...umm...work.
I AM using Dashbars with this, (with both its lodash.js and moment.js dependencies,) but this bug has existed since before I started using that library. FWIW, jQuery 2.1.3 IS installed, and loaded before any other library, and all of that is in the <head> tag. (I don't see where it would matter, but just in case.) And since JavaScript is involved, yes, I'm in Chrome. The version of Handlebars is the latest, 3.0.1, using the full version because my use-case doesn't allow pre-compiling. Another NB is that all of this is embedded in a .cfm file (not my choice,) so everything does get run through the CFML interpreter first.
So...I'd managed to outsmart myself again. I've created a fork of my original code, but HTTPS policy in my browser is keeping it from working =-\
The "money" differences are as follows (can't use SO's <ul> because I can't embed code in a bullet-block)
*I'd been trying to jam my template into a <tr> element, to avoid having Handlebars process more lines of code than I thought was necessary:
<tr class="searchResults" id="searchResultsHTML"></tr>
<script id="result-template" type="text/x-handlebars-template">
<!--- To accommodate for that this would all begin and end with a <tr>, I tried this: --->
{{#unless #first}}
<tr>
{{/unless}}
<!--- The rest of the template --->
{{#unless #last}}
</tr>
{{/unless}}
</script>
*In good-programmer fashion, I'd forked my actual file several times, trying different things. (Mostly did this to avoid endless git resetting and branching; I know git's meant for this sort of thing, but I just wanted to be able to refresh old and new tabs at once. Anyway!) Took out those {{unless}} blocks and...apparently, I'd misunderstood what that does (since the official documentation is a bit...scant...on that point. There's no TRUE inverse of {{#if}}) For the sake of those who don't want to bother clicking to the codepen:
<div class="searchResults" id="searchResultsHTML">
<script id="result-template" type="text/x-handlebars-template">
<table id="resultTable">
<tr>
<th>Personal Information</th>
<th>Education</th>
</tr>
<!--- The log tag DOES output all records, even the ones that aren't showing in the HTML. --->
{{#each this}} {{log #index}} {{log this}}
<tr>
<td>{{#with basicInformation}}
<p>{{MASTER_CUSTOMER_ID}} ({{CUSTOMER_STATUS_CODE}})<br />
{{SEARCH_NAME}}<br />
(<span class="lightBlue">ADD:{{ADDOPER}}–{{{d-format 'MM/DD/YYYY' (d-date 'YYYY-MM-DD' ADDDATE)}}}</span>)</p>
<p>DOB:{{{d-format 'MM/DD/YYYY' (d-date 'YYYY-MM-DD' BIRTH_DATE)}}}<br />
{{/with}}</td>
<!--- More table columns; six total --->
<td>{{#each education}}
<p>{{INSTITUTION_NAME}} ({{{d-format 'YYYY' (d-date 'YYYY-MM-DD' BEGIN_DATE)}}}–{{{d-format 'YYYY' (d-date 'YYYY-MM-DD' END_DATE)}}})</p>
{{else}}
<p>No education records found</p>
{{/each}}
</td>
</tr>
{{else}}
<tr class="alert largerError" id="errorMessageRow">
<td class="empty" id="errorMessage" colspan="6">Either there has been an error, or your search did not return any records from any datasource.</td>
</tr>
{{/each}}
</table>
</script>
Yes, I stuck with ColdFusion comments; since those are ONLY for my reference, or the poor next developer, they don't need to go to the client and that way Handlebars isn't taking valuable time rendering them. (I'm already annoyed Handlebars is going to have to churn through my header row and a bunch of other text.) This tool searches our databases for customer numbers that MIGHT represent accidental duplicate accounts, so if you search for John Smith...oi!
So for anyone who Googled their way over here...I'll be glad if this helps even one person avoid spinning their wheels the way I did.
I have a bunch of DOM like
<div>
<div class="stuff"/>
<div class="stuff"/>
<div class="stuff"/>
</div>
and I want to replace it with a new set of stuff
<div>
<div class="stuff"/>
<p class="stuff"/>
<ul class="stuff"/>
<a class="stuff"/>
</div>
Which will be fetched via Ajax. My question is: what is the best way to do this?
$.replaceWith doesn't quite do what I want, because I then end up with multiple copies of the new stuff.
I can guarantee that all the stuff will be in one contiguous block, and so presumably I could put in some placeholder after the last element (or before the first element) of the old stuff, remove the old stuff, and replace the placeholder with the new stuff.
However, this seems rather roundabout and inelegant. Is there any clever way of, removing all the old stuff and putting in a single copy of the new stuff, all at one go?
EDIT: I would also like to do this without using any container divs. Using container divs would work in the above case, but would fail in some cases, like when the stuff is inside a <table>:
<table>
<head/>
<body>
<tr/>
<tr class="stuff"/>
<tr class="stuff"/>
<tr class="stuff"/>
<tr/>
</body>
</table>
If i want to replace the rows labelled stuff with another set of rows, possibly more, possibly fewer, there is no way I can nicely put them in a container thingy without breaking the HTML, since the <body> can only contain <tr>s (IIRC).
$('#outerdiv').empty().append(newContent);
Unlike .html(), this will work regardless of whether newContent is an HTML string, or an existing DOM structure.
If there are multiple elements to be replaced but where you need to retain their siblings, you can do this:
$('.stuff').first().before(newContent).end().remove();
i.e. take the first .stuff element, add the new content before it, and then remove all the .stuff elements.
Yes: $('#tagetDiv').html(newContent)
One way to do it would be with wrapAll:
$('.stuff').wrapAll('<div/>').parent().replaceWith('<div class="stuff"/>');
I'm not sure if that passes the "elegant" test, but it does work regardless of whether there is any other content in the containing element.
With that said, though, this seems to be a very complicated solution to a simple problem. The simple solution would be to wrap your elements in a containing element; this shouldn't be a problem if, as you say, you can guarantee that they will always be together.
I am trying to use editInPlace JavaScript code with Python & Django on Google App Engine.
After editing the row of the table:
<table>
<tr id="editme" class="editme">
<td>Date</td>
<td>Description</td>
<td>Details</td>
</tr>
<tr id="editme" class="editme">
<td>Date</td>
<td>Description</td>
<td>Details</td>
</tr>
<tr id="editme" class="editme">
<td>Date</td>
<td>Description</td>
<td>Details</td>
</tr>
</table>
Which looks like this:
___ ___ ___
|___|___|___|
|___|___|___|
|___|___|___|
I maid that editInPlace JavaScript would save original string like "<td>Date</td><td>Description</td><td>Details</td>" by replacing it with striped string without <td> (ex. "Date Description Details") placing the string in to the <td colspan="3"><form>...</form></td> for editor to edit.
So here I prepared that the Http Response after submitting a new value would also be imitating 3 cols, I mean would have <td></td> tags (ex. "<td>ResponseDate</td><td>ResponseDescription</td><td>ResponseDetails</td>") to be placed in between <tr></tr> tags.
But the problem is such that after AJAX replacing values without refreshing hole page, gives me nasty table.
All the row in Chrome v12 is like moved a side and starts filling from the second col:
___ ___ ___
|___|___|___|___
___|___|___|___|
|___|___|___|
Please use Chrome Developer Tools to inspect the affected row after it has been edited (and displayed in the wrong way) - right-click on any cell and select "Inspect Element" in the popup menu. The DevTools window will show up, and you will be able to examine (in the Elements panel) whether the final DOM is correct. If it is, then it's a Chrome/WebKit bug.
Summary of my problem
After sometime debugging my issue i found my problem was caused by the following situation.
A class with a style content: "" being applied to a target TR prior to an ajax call which would replace the TDs with a fresh set of TDs, then, after removing that class I had the same problem as the OP; The end result was the shifting of the TDs to the right. The HTML on inspection was sound.
In detail this is what I had.
I had a TR which was my targetId container.
I had a TD with an ajax link that then returned a set of TDs to replace the old set within the targetId TR.
I am using jquery ajax and prior to the call I applied a class to the targetId TR, the class of which can be found in this answer and contains the content: "" style.
After the ajax call completes, removing that class.
This is what I ended up doing.
The ajax masking class I was using for the targetId, I replaced with a new class that just did some opacity. I kept the ajax masking class for the sender control.
Relating to the OP's problem
I downloaded and searched the "jquery-editinplace" the OP uses but could not find a content style being applied. Maybe someone with good search tools may find it. As stated in the comments above, the problem disappeared when chrome upgraded. This is my case of it remaining because of something possibly related.
I have not made a fiddle of this situation as I had trouble creating an ajax scenario. I would have liked to to prove it is a chrome bug and to submit it to Google.
Feel free to comment if something is unclear and I will update my answer accordingly.
To me, use same Id on multiple <tr> seems awkward.
It might cause some weird behavior.
Keep your unique Id per DOM.
Also I would use
<div>
Instead of tables
because with <div>, you can get more control with CSS.
HTML:
<div>
<div class="editme">
<div>Date</div>
<div>Description</div>
<div>Details</div>
</div>
<div class="editme">
<div>Date</div>
<div>Description</div>
<div>Details</div>
</div>
<div class="editme">
<div>Date</div>
<div>Description</div>
<div>Details</div>
</div>
</div>
CSS:
.editme { clear:both; }
.editme div { float:left; }
So after changing your HTML and CSS like this
you can simply replace those three divs
with a single DIV with FORM
Here is an example of DIV version