Template strings with JavaScript - javascript

I'm writing an application with some client-side JS that I use to update the DOM reasonably often.
The thing is that doing something like:
$('#id').html('<div class="' + class + '">' + content + '</div>');
multiple times and leaving HTML lying randomly round your JavaScript isn't very pretty and difficult to maintain.
Is there a JavaScript equivalent (or alternate solution) to the way Lithium handles this in it's view helpers.
See:
http://li3.me/docs/lithium/template/Helper::_render()
http://li3.me/docs/lithium/util/String::insert()
For examples.
Basically in the PHP version you would make an associate array of common strings and a simple method to replace to replace certain marked parts of those strings with variables of the same name.
Another silly example (psuedo-code:)
var strings = {
'div': '<div {:attr}>{:content}</div>'
};
console.log(render('div', {id: 'newElem'}, 'Hello, World!'));
// Output: <div id="newElem">Hello, World!</div>
If you have any better suggestions on how you handle storing HTML in your JavaScript and keep it from going all over the place then I'd very much like to hear it.

Yes, use jQuery templates or Underscore templates (my favorite) or any other JS templating engine out there.
Also, check this question for a discussion on performance of templating engines: Improve jQuery template performance

If you don't want to use a templating system, and have many html snippets that must be created many times, then you can use another technique :
Create a div in your main html file, give it a specific css class or id
Using css, make this div invisible
Inside is div, create the "template" divs, each one will contain a "snippet", each one with proper class or id
Using js (jquery, whatever) when you need it, clone the "template" div, append it where you need it, and then customize it.
Using jquery this is very easy, and your template "divs" are asy accessible to any html designer.
I'm on a mobile device now, and posting code snippets is a bit difficult, but let me know if want some examples.

jQuery encourages you to dynamically construct your DOM nodes instead of doing string concatenation:
$("#id").html(
$("<div />").addClass(class).text(content))
In general, you can use the jQuery attribute methods to construct such nodes, and many of these methods take mappings as you say you like. For example:
$("#id").append(
$("<div />")
.attr({id: "newElem"})
.css({width: "100%", color: "red"}))

Related

How can I make my Javascript code select all 'b' tags on a page instead of only the first one?

We have a very large website that is quite old and has a lot of 'b' tags. My boss wants to change them to 'strong' tags but this will require a lot of time to change manually so she was hoping we could change it with some code.
I had a nice bit of JQuery code that worked (intermittently), but I couldn't get it to work on the site as it uses JQuery 1.9.1 and cannot be upgraded.
I then found this piece of Javascript which does what I need but only works on the first 'b' tag on the page and all others stay as 'b' tags. I don't know enough about Javascript selectors to change the firstChild selector.
<script>
function replaceElement(source, newType) {
// Create the document fragment
const frag = document.createDocumentFragment();
// Fill it with what's in the source element
while (source.firstChild) {
frag.appendChild(source.firstChild);
}
// Create the new element
const newElem = document.createElement(newType);
// Empty the document fragment into it
newElem.appendChild(frag);
// Replace the source element with the new element on the page
source.parentNode.replaceChild(newElem, source);
}
// Replace the <b> with a <div>
replaceElement(document.querySelector('b'), 'strong');
</script>
You might use querySelectorAll:
Array.from(document.querySelectorAll('b')).forEach(e=>{
replaceElement(e, 'strong');
});
But this is really a xy question. You really should do the change server side, for example by using some search/replace (learn to use your code editor). You're adding to the code debt here.
Note also that there's no obvious reason to prefer strong over b in HTML5.
Use getElementsByTagName(). It's more efficient than querySelectorAll because it doesn't have to parse selectors, and it describes better what you are really trying to do - get elements by tag name.
var elements = document.getElementsByTagName("b");
replaceElement(elements[0], "strong");
replaceElement(elements[1], "strong");
replaceElement(elements[2], "strong");
You can also iterate over this collection by using Array.from().
You would be better off finding the source of the <b> tags and changing them there as Denys has mentioned.
Updating the DOM would have little benefit and would cause performance issues when there are many tags on a page.
Does this system use a CMS or database to store the content? I would look to use something like these 2 SQL queries to replace them across the site:
update content_table set content_column = replace(content_column, '<b>','<strong>');
update content_table set content_column = replace(content_column, '</b>','</strong>');

Do custom markup tags placed in an HTML document affect the flow and is it possible to parse them with JS? [duplicate]

This question already has answers here:
Is there a way to create your own html tag in HTML5?
(18 answers)
Closed 8 years ago.
Would it be possible to do the following
<body>
<main>
<!-- CONTENT -->
</main>
<foot>
<!-- FOOTER CONTENT -->
</foot>
</body>
if I then wrote some JavaScript that did something along the lines of the following. Please note that I don't want you to write the actual code that goes here. This is just a mockup of the core functionality.
for(elem inside main){
elem.makeItBig();
}
for(elem inside foot){
if(elem is img){
elem.makeItSmall();
}
}
I am aware of this post Is there a way to create your own html tag in HTML5?. But I don't really want to create tags to style them but rather to provide identifying attributes to the DOM which I can hook into using JavaScript. Imagine something kind of like a class, but used in a way that you can stitch lots of PHP generated parts together using these tags.
If you use a made up tag in HTML is it ignored by your browser or will it throw an error.
You can use your own tags as far as I'm aware.
You'd need to do some mucking about to get them to work in older IE browsers.
The more important point is - why on earth would you want to? It wouldn't make your code very maintainable or future-proof. Just use classes on proper elements.
Can you create custom tags? yes. Is it a good idea? not really because your tag may not be recognized by some browsers as a valid html standard. you can check this: http://www.w3.org/MarkUp/html-spec/html-spec_4.html#SEC4.2.1
For custom elements specifications you can look at standards specification for custom elements : http://w3c.github.io/webcomponents/spec/custom/
Although your approach seems nice, just think about changing the size of another group of elements ... you would probably use the same function so why not do this:
var makeItBig = function(elem){...};
for(elem in main){
makeItBig(main[elem]);
}
this way you won't have to create a new method for each element you need to change.
But if you really need it that way you can make it like this:
var makeItBigFunction = function(){var elem = this; ...};
// create new methods
for(elem in main){
main[elem].makeItBig = makeItBigFunction;
}
// make use of them
for(elem in main){
main[elem].makeItBig();
}
Notice that there is a big difference between DOM object's properties (or methods) and HTML attributes.
Read more about it: Properties and Attributes in HTML
Feel free to use HTML5 tags like <content>, <header>, <footer>, <aside> etc.
You can read more about them here: http://www.w3schools.com/html/html5_new_elements.asp in section "New Semantic/Structural Elements". Those should be considered as supported in most modern browsers. Actually, you may use any other custom tags, however their default properties (display, position etc.) may be unpredictable.

jQuery append text formatting

This question is not related to coding issues but how we write our codes. For example take the append function. When we use jQuery append to insert long divs, it is easy to lose track of it's correctness. Example:
$('#someDiv').append('<div><span><div> .............. hundreds of div here ..... </div></span></div>');
Is it possible to convert this to a readable format, for example using multi-lines. I tried
$('#someDiv').append('<div>'+
+'<span>'+
+'<div> ...... and you get the point')
This doesn't seem to work. This question may be easy for some but it is not so obvious for me. Also although I minify js files at the end, it would be nice not to lose track of the elements while writing the code.
If you have to add the HTML inline style I would suggest the following format.
var html =
'<div class="somediv">\
<div class="otherdiv">\
.
..
...
</div>\
</div>';
$('#somediv').append(html);
You can do it this way -
$('#someDiv').append($('<div>').append($('<span>'))
.append($('<div>'))
.append($('<div>'))
.append($('<div>'))
.append($('<div>'))
)
You can also add css styles, add class, change html while appending these html elements (wrapped in jQuery object)
$('<div>').css('color','red')
$('<div>').addClass('someClass')
$('<div>').html("and you get the point")
My solution would be to create all these elements
div1 = $(document.createElement('div'));
div1.attr(..);
div1.css(..);
container.append(..)
This means a lot of code but you can outsource it, can easily change attributes and its good readable...

About good practices for creating and appending elements with JS

Example code
var jqxhr=$.getJSON("http://search.twitter.com/search.json?callback=?",{q:query},
function(data) {
... question.
});
Question
Now i need to create for each tweet result something like this (for example...)
<article class="tweet">
<header>
<img class ="tweet_img"src="data.profile_image_url"/>
</header>
<p class="tweet-text">data.text</p>
</article>
Well, i know several ways to append each result to the document:
Creating a big HTML string and add the data from JSONP and append this to some container.
Create a p element, a header element... work with them and after that append a final Element to some container.
Now the question is: with your experience what is the correct way to do this?
I mean the correct way using good principles.
Please dont ask about the html, it's dumb example.
Thanks.
Well, best practices will tell you not to use the innerHTML property of a DOM element, which is what you'd be doing with option 1. But unless you are concerned about immediately operating on the code with Javascript, attaching events, or security concerns around tag injection (I don't know how much this is an issue anymore) then creating an HTML string and inserting it using innerHTML is going to be a lot quicker and easier to update.
There are several valid approaches that each have their own advantages...
The technique of just generating the HTML as a string in your java code and adding it with .innerHTML is known to be one of the fastest performing approaches...but it provides very little validation of your HTML.
Alternatively, you can build the HTML using DOM methods directly, creating tags and appending them to build the structure. This is generally safer in that you have more validation going on, but the DOM methods are extremely wordy, which makes them a bit painful to type...and the code is even more verbose as you have to add attributes one at a time as well.
My personal preference, especially since you're already using JQuery, would be to build the tags and text nodes using JQuery, and put them together using JQuery, which allows you to do so in bite-sized, more human-verifiable units, without becoming overly verbose.
This also has the advantage that JQuery's methods of producing new tags give you additional support for older browsers that did not adhere to DOM standards. Hopefully you don't actually have to care whether your page works for those older browsers, but more compatibility never hurts either.
In that approach, you'd write something like the following:
var article = $('<article class="tweet"></article>');
var header = $('<header></header>');
var image = $('<img class="tweet_img" src="' + data.profile_image_url + '"></img>');
var tweet = $('<p class="tweet-text">' + data.text + '</p>');
header.append(image);
article.append(header, tweet);
$("#id_of_content_area_to_add_the_tweet_to").append(article);
The cleanest way I know how is to use a template system like Mustache, instead of "HTML in JS"
var template = html_string, //HTML from a string or from AJAX
data = {...data...}, //structured data
html = $(Mustache.render(template,data)); //wrap in jQuery to operate
html.appendTo(somewhere_in_DOM);
If you want to attach some event handlers to the elements then you should generate them separately.
But if you don't want to attach any event handler then i will recommend first method
$("body").append('<article class="tweet"><header><img class ="tweet_img" src="'+data.profile_image_url+'"/></header><p class="tweet-text">'+data.text+'</p></article>')
I will recommend you to use some Template engine like Handlebars.js Which is the right solution for your problem.
Which is having many more options which has many more conditional options which can be useful in feature. Just visit the above link you will have some idea.

Updating HTML via JSON/AJAX

I've been using JSON to handle AJAX functionality in my rails applications ever since I heard about it, because using RJS/rendering HTML "felt" wrong because it violated MVC. The first AJAX-heavy project I worked on ended up with 20-30 controller actions tied directly to specific UI-behaviors and my view code spread over controller actions, partials and rjs files. Using JSON allows you to keep view specific code in the view, and only talk to view agnostic/RESTful controller actions via AJAX to get needed data.
The one headache I've found from using pure JSON is that you have to 'render' HTML via JS, which in the case of AJAX that has to update DOM-heavy elements, can be a real pain. I end up with long string building code like
// ...ajax
success: function(records){
$(records).each(function(record){
var html = ('<div id="blah">' + record.attr +
etc +
')
})
}
where etc is 10-15 lines of dynamically constructing HTML based on record data. Besides of the annoyance, a more serious draw back to this approach is the duplication of the HTML structure (in the template and in the JS).* Is there a better practice for this approach?
(My motivation for finally reaching out is I am now tasked with updating HTML so complex it required two nested loops of Ruby code to render in the first place. Duplicating that in Javascript seems insane.)
One thing I've considered is loading static partial files directly from the file system, but this seems a bit much.
I like the idea of templating. In my experience it can really clean up that messy string manipulation!
There are many solutions, for example, check out John Resig's (creator of jQuery):
http://ejohn.org/blog/javascript-micro-templating/
I would go with creating an HTML structure that contains placeholders for the elements you'll need to update via AJAX. How much structure it applies will depend on what you're updating; if you know the number of elements you'll have ahead of time, it would be something to the effect of
<div id="article1">
<div id="article1Headline"></div>
<div id="article1Copy"></div>
<div id="article1AuthorInfo"></div>
</div>
<div id="article2">
<div id="article2Headline"></div>
<div id="article2Copy"></div>
<div id="article2AuthorInfo"></div>
</div>
You then write code that references the id of each element directly, and inserts into the .innerHTML property (or whatever syntactically more sugary way jquery has of doing same thing). IMHO, it's not really so terrible to have to assign the contents of each element, the part that you don't want to have to sprinkle through your AJAX functions is the HTML structure itself; in your app the content is volatile anyway.
However, it looks like you might have a list of an unknown number of elements, in that case it may be that you'd need to just put in a placeholder:
<div id="articleList"></div>
In that case I don't really see a way to avoid building the HTML structure in the javascript calls, but a reasonable amount of decomposition of your javascript should help that:
function addArticle( headline, copy, authorInfo, i ){
createDiv( "article" + i + "Headline", headline );
createDiv( "article" + i + "Copy", copy);
createDiv( "article" + i + "AuthorInfo", authorInfo );
}
(not working code of course, but you get the idea,)
You could use the load function in jQuery;
This loads the content of a page into a div like this:
$('#content').load("content/" + this.href.split('#')[1] + ".html", '', checkResponse);
Just make a dynamic view and you are good to go...
Just happened to find exactly what I was looking for: Jaml

Categories