Code refactoring a long JavaScript string so its easier to style - javascript

I am wondering if there is a better way to write this JavaScript (Jquery) code.
This snippet dynamically created a H3 with a link.
My designer is going nuts trying to style this as its in JavaScript.
I am trying to re-write / refactor this into to smaller chunks to allow my designer to style without looking at all this code on one single line.
var dvClassContainer = $(document.createElement('div')).attr("id", 'dvclassconatiner_' + classVal).attr("classifname", classifname).attr("memclassnumber", memclassnumber).html('<h3>' + classifname + '<a id="ancclassremove_'+ classVal +'" classVal="' + classVal + '" onclick="RemoveClassificationUponConfirm(\'' + classVal + '\');" class="buttons delete btnSmall">Delete</a></h3><img style="display:none;" id="imgloadRemClass_' + classVal + '" alt="loading" src="../Images/application/smallUploading.gif" />');
I was thinking of creating more variables and combining them together.
Is there a 'cleaner' way of writing this?

If you utilize more of jQuery's features, the code becomes more readable and more easily maintained:
var dvClassContainer = $('<div>');
dvClassContainer.attr({
id: 'dvclasscontainer_'+classVal,
classifname: classifname,
memclassnumber: memclassnumber
});
var dvHeader = $('<h3>');
var dvHeaderLink = $('<a>Delete</a>');
dvHeaderLink.attr({
id: 'ancclassremove_'+classVal,
classVal: 'classVal',
class: 'buttons delete btnSmall'
}).on('click',function(){
RemoveClassificationUponConfirm(classVal);
});
var dvImg = $('<img>');
dvImg.attr({
id: 'imgloadRemClass_'+classVal,
alt: 'loading',
src: '../Images/application/smallUploading.gif'
});
dvClassContainer.append(dvHeader.append(dvHeaderLink.append(dvImg)));
Ideally, you would also want to move all those non-standard attributes (classifname, memclassnumber, classVal) to data- attributes, which would be accessible via jQuery's data() function.

var dvClassContainer = $(document.createElement('div'))
.attr("id", 'dvclassconatiner_' + classVal)
.attr("classifname", classifname)
.attr("memclassnumber", memclassnumber)
.html('<h3>' + classifname + '<a id="ancclassremove_'+ classVal +'" classVal="' + classVal + '" onclick="RemoveClassificationUponConfirm(\'' + classVal + '\');" class="buttons delete btnSmall">Delete</a></h3><img style="display:none;" id="imgloadRemClass_' + classVal + '" alt="loading" src="../Images/application/smallUploading.gif" />');
The last line still needs fixing. I would create elements and then set their attributes and then append them to the h3. You can do that using var h3 = $("<h3></h3>"); (as an example) and set attributes using .attr() and finally .append() to put it all together.

I'm going to go a different way with this, after acknowledging that this one line of code is nasty.
It's not the JavaScript that's giving your designer headaches. If they can't style this with CSS, they're not trying hard enough. Surely that h3 and anchor are inside other elements that they can grab for some styling:
.someContainer h3 { color: chartreuse; }
However, if they HAVE tried everything possible, you still just need to add a new class or two (to the h3 and the anchor). Where you have .html('<h3>'... you would change it to .html('<h3 class="someClass">'...
As much as we have fun optimizing and downright fixing bad JS in poor implementations, if we assume that this is "working", the problem is the designer's ability to style. This is therefore not really a JavaScript issue.

Use Douglas Crockford's Supplant method. It tokenizes a string so you can dynamically build strings out. Here is a fiddle example: http://jsfiddle.net/mmeah/F23rk/
// http://javascript.crockford.com/remedial.html
if (!String.prototype.supplant) {
String.prototype.supplant = function (o) {
return this.replace(/{([^{}]*)}/g,
function (a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
}
);
};
}
var classVal="x", classifname="y", memclassnumber="z"; //predefined
var dvClassHtml = $("#someDiv").html();
$("#someDiv").html("");
var params ={
"classVal":classVal,
"classifname":classifname,
"memclassnumber":memclassnumber
};
dvClassHtml=dvClassHtml.supplant(params);
var dvClassContainer =
$(document.createElement('div'))
.attr("id", 'dvclassconatiner_' + classVal)
.attr("classifname", classifname)
.attr("memclassnumber", memclassnumber)
.html(dvClassHtml);

var dvClassContainer = $('<div/>')
.attr({'id': 'dvclassconatiner_' + classVal,
'classifname': classifname,
'memclassnumber': memclassnumber
})
.html(
function() {
var $title = $('<h3>' + classifname + '</h3>');
var $link = $('<a>Delete</a>').attr({
'id': 'ancclassremove_' + classVal,
'classVal': classVal,
'class': 'buttons delete btnSmall'
})
.on('click', function() {
RemoveClassificationUponConfirm(classVal);
});
var $img = $('<img/>').attr({
'id': 'imgloadRemClass_' + classVal,
'alt': 'loading',
'src': '../Images/application/smallUploading.gif'
})
.css('display', 'none');
return $title.append($link).add($img);
});
Demo

Related

How to concatenate and pass parameters values in html using jQuery

I'm using jQuery to get values from ajax rest call, I'm trying to concatenate these values into an 'a' tag in order to create a pagination section for my results (picture attached).
I'm sending the HTML (divHTMLPages) but the result is not well-formed and not working, I've tried with double quotes and single but still not well-formed. So, I wonder if this is a good approach to accomplish what I need to create the pagination. The 'a' tag is going to trigger the onclick event with four parameters (query for rest call, department, row limit and the start row for display)
if (_startRow == 0) {
console.log("First page");
var currentPage = 1;
// Set Next Page
var nextPage = 2;
var startRowNextPage = _startRow + _rowLimit + 1;
var query = $('#queryU').val();
// page Link
divHTMLPages = "<strong>1</strong> ";
divHTMLPages += "<a href='#' onclick='getRESTResults(" + query + "', '" + _reg + "', " + _rowLimit + ", " + _startRow + ")>" + nextPage + "</a> ";
console.log("Next page: " + nextPage);
}
Thanks in advance for any help on this.
Pagination
Rather than trying to type out how the function should be called in an HTML string, it would be much more elegant to attach an event listener to the element in question. For example, assuming the parent element you're inserting elements into is called parent, you could do something like this:
const a = document.createElement('a');
a.href = '#';
a.textContent = nextPage;
a.onclick = () => getRESTResults(query, _reg, _rowLimit, _startRow);
parent.appendChild(a);
Once an event listener is attached, like with the onclick above, make sure not to change the innerHTML of the container (like with innerHTML += <something>), because that will corrupt any existing listeners inside the container - instead, append elements explicitly with methods like createElement and appendChild, as shown above, or use insertAdjacentHTML (which does not re-parse the whole container's contents).
$(function()
{
var query=10;
var _reg="12";
var _rowLimit="test";
var _startRow="aa";
var nextPage="testhref";
//before divHTMLPages+=,must be define divHTMLPages value
var divHTMLPages = "<a href='#' onclick=getRESTResults('"+query + "','" + _reg + "','" + _rowLimit + "','" + _startRow + "')>" + nextPage + "</a>";
///or use es6 `` Template literals
var divHTMLPages1 = `` + nextPage + ``;
$("#test").append("<div>"+divHTMLPages+"</div>");
$("#test").append("<div>"+divHTMLPages1+"</div>");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="test"></div>

How to properly generate HTML in a JavaScript widget?

I've been following this tutorial on how to make JS widget. However I noticed that manually building html with plain JavaScript is not DRY. I am planning to build a form, tables etc. in a JS widget. Whats the best way to do this?
$.getJSON(jsonp_url, function(data) {
var fruits = ["Apples", "Mangoes", "Banana"];
var myHtml = "<ul>";
$(fruits).each(function(i){
myHtml += "<li>" + fruits[i] + "</li>";
});
myHtml += "</ul>";
$('#example-widget-container').html(myHtml);
});
if you want one of your divs or containers to continuously grow while you build dynamic content, without losing older content, use jQuery.append
$('#example-widget-container').append(myHtml);
this is probably the cleanest way. Or you can do other things like
var html = $('#example-widget-container').html();
newHtml = yourContent;
$('#example-widget-container').html(html + newHtml);
In JavaScript you can generate html content in different ways :
Create HTML with a string directly :
$("#sampleArea").append('<div class="' + newClass + '">' + newText + '</div>');
Create HTML with jQuery Api wrapping :
$("#sampleArea").append($('<div/>',{class : newClass}).text(newText));
Use a template engine in Javascript (like mustache.js) :
<script id="exampleTpl" type="x-tmpl-mustache">
<div class="{{class}}">{{text}}</div>
</script>
<script>
var data = {
class: newClass,
text: newText
}
var template = $('#exampleTpl').html();
var html = Mustache.render(template, data);
$('#sampleArea').append(html);
</script>
The best solution will depends of your use.

Printing JSON object with jQuery into html

I have a JSON object that looks like this:
var content = '[{"title":"John Apple","lastname":"Apple"},
{"title":"Kumar Patel","lastname":"Patel"},
{"title":"Michaela Quinn","lastname":"Quinn"},
{"title":"Peyton Manning","lastname":"Manning"},
{"title":"John Doe","lastname":"Doe"},
{"title":"Jane Lee","lastname":"Lee"},
{"title":"Dan McMan","lastname":"McMan"},
{"title":"Yu Win","lastname":"Win"}]';
And I am trying to edit it with jQuery to display in my div tag with the id of content-view
here is my jquery:
$.each(content, function(t, l){
$('#view-content').appendTo('<div id = "' + l + '">' + t + '</div>');
});
For some reason on my jsFiddle, which is right here: http://jsfiddle.net/gAWTV/
It just comes up blank with the result. Does anyone have any ideas? I am stumped...
---EDIT---
What i would like to do is have everything output into its own div tags like this:
<div id="Apple">John Apple</div>
<div id="Patel">Kumar Patel</div>
<div id="Quinn">Michaela Quinn</div>
etc...
Your content is a string, not an array of objects.
You firstly need to store it as an array, so get rid of the single quotations marks.
var content = [{"title":"John Apple","lastname":"Apple"},
{"title":"Kumar Patel","lastname":"Patel"},
{"title":"Michaela Quinn","lastname":"Quinn"},
{"title":"Peyton Manning","lastname":"Manning"},
{"title":"John Doe","lastname":"Doe"},
{"title":"Jane Lee","lastname":"Lee"},
{"title":"Dan McMan","lastname":"McMan"},
{"title":"Yu Win","lastname":"Win"}];
Unless there is a reason you store it as a string? Then you need to parse it.
var content_object = JSON.parse(content);
Then you can run your code. However, I think you want to "stringify" your JSON. If that's the case you also need to swap t with l, because l is the object. Finally, you want to append, not appendTo. The latter appends the subject to the target you specify, not the other way round (so in your case appendTo appends #view-content to your div you've constructed, which doesn't work).
$.each(content, function(t, l){
$('#view-content').append('<div id = "' + t + '">' + JSON.stringify(l) + '</div>');
});
JSFiddle
Final comment, I would use document fragments to build your list instead of appending the new divs to an existing one in the each loop - that improves performance.
After OP edit:
Change the last snippet to:
$.each(content, function(t, l){
$('#view-content').append('<div id = "' + l.lastname + '">' + l.title + '</div>');
});
Updated JSFiddle
Try this:
var content = [{"title":"John Apple","lastname":"Apple"},
{"title":"Kumar Patel","lastname":"Patel"},
{"title":"Michaela Quinn","lastname":"Quinn"},
{"title":"Peyton Manning","lastname":"Manning"},
{"title":"John Doe","lastname":"Doe"},
{"title":"Jane Lee","lastname":"Lee"},
{"title":"Dan McMan","lastname":"McMan"},
{"title":"Yu Win","lastname":"Win"}];
$.each(content, function(t, l){
$('<div/>',{
id: l,
text:t }).appendTo('#view-content');
});
DEMO

Generating a string of jQuery for Ajax uploading

My page generates a jQuery string (the jqueryBlock below) that gets ajaxed up to a php file that writes it into a new html file, where it will execute. The code "A" below is what I have now to generate the final jQuery, "B" below in the new html file.
"A"
var targetName = "redbox";
target = $('div[filename=' + targetName + ']').hide()[0];
var jqueryBlock= '<script>$(function() {\n';
jqueryBlock += "$('#" + this.id + "').click(function() {\n";
jqueryBlock += "$('#" + target.id + "').show();\n";
jqueryBlock += "}).css('cursor', 'pointer');\n";
jqueryBlock += "$('#" + target.id + "').dblclick(function(){\n$(this).hide();\n});\n";
jqueryBlock += "})<\/script>";
"B"
<script>$(function() {
$('#T_1376594221987').click(function() {
$('#T_1376594237267').show();
})
.css('cursor', 'pointer');
$('#T_1376594237267').dblclick(function(){
$(this).hide();
});
})</script>
This all works, but it's a nightmare to write block A, trying to keep track of the multiple levels of quotes and all the parens and braces and not being able to break lines to make them more readable. I'm thinking that there must be a way to do this where I can write something that looks more like the finished jQuery for "A". Can anyone suggest a better method?
Thanks.
Ok, well... I came up with some ideas... you may like some, all, or none of it. But I figured I'd paste it here. Just a couple of techniques. You can view the JsFiddle as well.
The first, make a function for creating the jQuery selector. This way you can just pass the id, and get your selector, no quotes to worry about.
function makeJqIdSelector(id) {
return "$('#" + id + "')";
}
The same way of thinking, you could write functions to wrap something in <script> tags (or even a function.
function wrapScriptTags(scr) {
return "<script>\n" + scr + "\n<\/script>";
}
Finally, you can use an array to join the elements so you don't have to keep typing out \ns. ie:
var arr = [];
arr.push("a",
"b",
"c"
);
var str = arr.join("\n");
//output:
//a
//b
//c
This has the added effect of being more efficient as well. (probably not an issue for modern browsers, and especially not for this few strings)
Here it is all together:
var thisSelect = makeJqIdSelector(this.id);
var targetSelect = makeJqIdSelector(target.attr('id'));
var jblock = [];
jblock.push(
"$(function() {",
thisSelect + ".click(function() {",
targetSelect + ".show();",
"}).css('cursor', 'pointer');",
targetSelect + ".dblclick(function(){\n$(this).hide();",
"});",
"});"
);
var jqueryBlock = wrapScriptTags(jblock.join("\n"));
output
<script>
$(function() {
$('#T_1376594221987').click(function() {
$('#T_1376594237267').show();
}).css('cursor', 'pointer');
$('#T_1376594237267').dblclick(function(){
$(this).hide();
});
});
</script>
Note: Obviously, I did not spend a lot of time making sure the output was perfect. It was just for the technique - I have no real way of testing it.
If I understanded everything, you could ajax up only the dynamic variables to the PHP file, and change it to something like this:
<script>$(function() {
$('#<?php echo $_GET['id']; ?>').click(function() {
$('#<?php echo $_GET['id']; ?>').show();
})
.css('cursor', 'pointer');
$('#<?php echo $_GET['id']; ?>').dblclick(function(){
$(this).hide();
});
})</script>
In coffeescript you can use a text block that keeps track of the indention level for you. Maybe you can change to coffeescript just for this script.
http://coffeescript.org/#strings

jQuery replace hyphens with spans for blogger date header

I'm looking to customize the default date header in blogger with jQuery.
The original output is:
<h2 class='date-header'>2011-01-20</h2>
I want to wrap the YYYY, MM, and DD in spans so I can manipulate them as child nodes.
The result would be:
<h2 class='date-header'><span class="dhy">2011</span><span class="dhm">01</span><span class="dhd">20</span></h2>
Each attempt of mine adds extra tags so it's a nested mess.
Anybody have a good solution?
Here's a nice functional solution:
$('.date-header').html(function() {
var txt = $(this).text();
var classes = ['dhy', 'dhm', 'dhd'];
$(this).html($.map(txt.split(/-/), function(val) {
return $('<span/>', {'class': classes.shift()}).text(val)[0];
}));
});
http://jsfiddle.net/ThiefMaster/WdRAw/
If it always has the same format of YYYY-MM-DD then you could use split to get the elements, loop through them, create your output HTML then add that as the HTML of the h2.
$(function()
{
$(".date-header").each(function()
{
var arrDate = $(this).text().split("-");
var strOut = '<span class="dhy">'+arrDate[0]+'</span>-';
strOut+= '<span class="dhm">'+arrDate[1]+'</span>-';
strOut+= '<span class="dhd">'+arrDate[2]+'</span>';
$(this).html(strOut);
});
});
And a fiddle: http://jsfiddle.net/ahallicks/xGa2J/2/
I think this should do it:
var header = $('.date-header');
var d = header.text().split('-');
header.html('<span class="dhy">' + d[0] + '</span><span class="dhm">' + d[1] + '</span><span class="dhd">' + d[2] + '</span>');

Categories