Best way to handle concatenating string with another function - javascript

I am working on cleaning up some adopted code - there is a lot of duplication.
There is a set of jQuery callbacks where we get back JSON like this:
[
{"location":{"id":164,"name":"place 1"},"users":[{"id":1,"name":"joe"},{"id":2,"name":"jack"}]},
{"location":{"id":162,"name":"place 2"},"users":[{"id":3,"name":"joe"},{"id":4,"name":"jon"}]}
]
I go through with these functions:
function locations_view(r) {
str = "";
$.each(r.data, function(k, v) {
str += v.location.name + "<br />";
iterate_users(v.users);
});
$("#locations").html(str);
}
function iterate_users(users) {
str += '<strong>users:</strong>' + users.length + '<br />';
$.each(users, function(k1, v1) {
str += "<a href='/users/" + v1.id + "'>" + v1.name + "</a> ";
});
str += "<br />";
}
This seems to work but it looks a little ugly. Is there a better way to do this. Also, I want to minimize memory consumption (returning the string rather than have a global str was causing performance issues). Is there a better, more elegant way to do this? Would having multiple copies of str ever cause a problem? Like if I have products_view that also uses a str?

It might be a bit faster doing concatenation in one step, like
function locations_view(r) {
var peices = [], br = "<br />";
$.each(r.data, function(k, v) {
peices.push(v.location.name, br);
peices.push.apply(peices, iterate_users(v.users));
});
$("#locations").html(peices.join(""));
}

Yes, if something else uses str in the wrong way (i.e. also globally) then that will cause a problem. Best not to have any globals at all. You could change them to this:
function locations_view(r) {
var str = "";
$.each(r.data, function(k, v) {
str += v.location.name + "<br />";
str += iterate_users(v.users);
});
$("#locations").html(str);
}
function iterate_users(users) {
var str = '<strong>users:</strong>' + users.length + '<br />';
$.each(users, function(k1, v1) {
str += "<a href='/users/" + v1.id + "'>" + v1.name + "</a> ";
});
return str + "<br />";
}
And that would be much better. If there are other functions that use iterate_users, they'll need to be changed too.
Also, if you're not already doing this, consider escaping the HTML in v1.name to prevent script injection. You could also use jQuery/DOM manipulation instead.

I've cleaned up your code:
function locations_view(r){
var str = ""; // don't forget var
$.each(r.data, function(k,v){
str += v.location.name + "<br />";
str += iterate_users(v.users); // iterate_users now returns a string, concat it
});
$("#locations").html(str);
}
function iterate_users(users){
var str = '<strong>users:</strong>' + users.length + '<br />'; // redefine str locally
$.each(users, function (k1,v1){
str += '' + v1.name + ' '; // flipped use of ' and ", it's more correct
});
return str + "<br />"; // return str
}
I don't see much wrong with it. I suppose there might be more efficient ways to do it, buy why? This seems like a decent and most importantly: obvious way to do it.
Also, JSLint, it will hurt your feelings but save you headaches

function locations_view(r) {
var $loc = $("#locations");
$.each(r.data, function (k, v) {
$loc.append(v.location.name + "<br/>");
$loc.append('<strong>users:</strong>' + v.users.length + '<br />');
$.each(v.users, function (k1, v1) {
$loc.append("<a href='/users/" + v1.id + "'>" + v1.name + "</a> ");
});
$loc.append("<br />");
});
}

Related

Building html output with a input checkbox with javascript

I'm building a string that will be place in a div pro grammatically. I am trying to call the onclick attribute of the input checkbox and having a little bit of trouble. I am trying to pass a unique value id with each checkbox click. The code below is what I'm using. See below for the problem:
var count = 1;
$.each(JSON.parse(data.d), function (k, v) {
var searchName = v.searchName;
resultString += "<div class='row form-group'>";
resultString += "<div class='col-sm-1 right-content'><input type='checkbox' onclick = 'authorCheckboxclick(this)' id='" + searchName + "'></div>";
resultString += "<div class='col-sm-11'>";
resultString += "<span>";
//resultString += v.text
resultString += count + ". " + v.text
resultString += "</span>";
resultString += "<br />";
resultString += "<span>";
//resultString += "Consectetur adipisicing, Consequatur, 2015.";
resultString += "</span>";
resultString += "</div>";
resultString += "</div>";
//resultString += "<br><br>";
count++;
});
In the authorCheckboxclick function if I put var answerid = $(this).attr('id'); I get undefined.
function authorCheckboxclick(elem) {
var answerid = $(this).attr('id');
alert(answerid); //I get undefined
var answerid = $(this).attr(elem.id);
alert(answerid); //I get undefined
var answerid = $(this).attr(elem.id);
alert(answerid); //I get undefined
var searchTerm = elem.id;
alert(searchTerm); //I get proper value
searchTerm = searchTerm.substring(0, 3);
alert(searchTerm); //I get proper value
var answerid = $(this).attr(elem.id);
alert(answerid); //I get undefined
var search = searchTerm.toUpperCase();
var array = jQuery.grep(dataMembers, function (value) {
return value.toUpperCase().indexOf(search) >= 0;
});
Is there a reason my jQuery call is not working and my JavaScript is? Is there a best practice to send the id value to a junction? Am I mixing Apples with Orange? Which method show be faster?
The immediate solution to your problem is that you're using the this keyword in your function. As you are calling the function from an on* attribute the scope of the function will be the window, not the element that raised the event. To fix this, simply use the element you provide in the parameter, ie. $(elem) instead of $(this).
A better solution entirely would be to use an unobtrusive delegated event handler which can utilise the this keyword as you're attempting to. It also has the benefits of leaving cleaner HTML code and being a better separation of concerns. Try this:
var count = 1;
$.each(JSON.parse(data.d), function(k, v) {
var searchName = v.searchName;
resultString += '<div class="row form-group">' +
'<div class="col-sm-1 right-content"><input type="checkbox" id="' + searchName + '"></div>' +
'<div class="col-sm-11">' +
'<span>' + count + ". " + v.text + '</span><br />' +
'<span></span>' +
'</div>' +
'</div>';
count++;
});
$(document).on('change', '.row :checkbox', function() {
var answerid = this.id;
var search = searchTerm.toUpperCase();
var array = jQuery.grep(dataMembers, function(value) {
return value.toUpperCase().indexOf(search) >= 0;
});
});

this.id is not working to detect which link is clicked in href

I am new to javascript and I am creating a bookstore using the google API. I have a small issue which I couldn't figure out. In the below piece of code that I saw from example code of google api bookstore function, I am trying to create href for the title of the book and pass its selfLink to the destination page i.e book-description.html.
When I put alert(this.id) on onclick It works, but for a normal method get(this) it does not work. I do not need an alertbox I want to take the id of the link clicked in href and pass it to another html.
handleResponse(response) {
for (var i = 0; i < response.items.length; i++) {
var item = response.items[i];
var a = item.volumeInfo.title;
var selfL = item.selfLink;
//var b = a.link("book-description.html");
var image = item.volumeInfo.imageLinks.smallThumbnail;
document.getElementById("content").innerHTML += "</br>" + "</br>" + "<br>" + "<img src =" + "'" + image + "'" + " class='im'/>";
document.getElementById("content").innerHTML += "<h4 class='right'>" + "<a href = 'book-description.html'id = " + "'" + selfL + "'" +
"onclick ='get(this);'>" + a + "</a></h4>";
function get(e) {
var link = e.id;
localStorage.setItem("Link", link);
}
document.getElementById("content").innerHTML += "<h4 class='right'>" + "AUTHOR:" + item.volumeInfo.authors + "</h4>";
document.getElementById("content").innerHTML += "<h5 class='right'>" + "PUBLISHER:" + item.volumeInfo.publisher + "</h5>";
var rating = item.volumeInfo.averageRating;
if (rating) {
document.getElementById("content").innerHTML += "<h5 class='right' id='rating'>" + rating + "</h5>";
} else {
document.getElementById("content").innerHTML += "<h5 class = 'right' id ='rating'>Not Rated Yet</h5>";
}
//document.getElementById("content").innerHTML += "<br>" + "<br>" + "<br>" + item.volumeInfo.publisheddate;
}
}
There are a number of problems with your code, but specifically in answer to your question; your function get is scoped so it is only available within the function handleResponse. For it to be accessible from an onclick it must be in page scope.
Simply move this
function get(e) {
var link = e.id;
localStorage.setItem("Link", link);
}
Into the head of your page
In programming there is the concept of DRY (Don't repeat yourself). So store a reference to document.getElementById("content") and reuse that variable.
var content = document.getElementById("content");
content.innerHTML = ...
You're missing some spaces in your output html. This may work in some browsers, others will struggle
<a href = 'book-description.html'id=
Should have a space between the end of one attribute and the start of another
<a href='book-description.html' id=
And for heaven sake, sort out the concatenation of your strings. You dont need a + if its just a simple string
document.getElementById("content").innerHTML += "</br>" + "</br>";
should be
document.getElementById("content").innerHTML += "</br></br>";

Convert Snippet of JS to JQuery

I want to convert the javascript code below to it's equivalent in JQuery.
Here's the snippet:
<script>
var str = '';
var elem = document.getElementById('formID').elements;
for(var i = 0; i < elem.length; i++)
{
str += "<b>Input Type:</b>" + elem[i].type + "&nbsp&nbsp";
str += "<b>Input Name:</b>" + elem[i].name + " ";
str += "<b>current Value:</b><i>" + elem[i].value + "</i> ";
str += "<br>";
}
document.getElementById('lblValues').innerHTML = str;
</script>
You can see I'm displaying what Inputs are within a Form element.
But I've reached my understanding of Loops and Elements of an Object. (especially form elements)
<script>
.........
// this much I know!
$("div#lblValues").html(str);
</script>
You can use $("#formID input") selector, this will return an array of inputs inside the form named 'formID'. Then, you can use each function to iterate over it. Hope this helps!
str = ""
$("#formID input").each(function(elem){
str += "<b>Input Type:</b>" + elem.type + "&nbsp&nbsp";
str += "<b>Input Name:</b>" + elem.name + " ";
str += "<b>current Value:</b><i>" + elem.value + "</i> ";
str += "<br>";
})

jQuery/JSON data not looping in created HTML

Currently trying to loop through a JSON file and for each object, create a article tag around the data as I format it with HTML, I am successful and creating the first article tag but the I cannot loop through to the next object with the $.each function
HTML code
<body>
<div id='container'>
<div id='content'>
<article class='tumblrPost'>
<header>
<h1> Dragonball Z Motivation </h1>
</header>
<img src='images/dragonball_z.jpg' alt='dragonball z' title='dbz' />
<footer>
<h1> Watch the Video Life & Motivation with Dragonball Z </h1>
</footer>
</article>
</div>
</div>
</body>
</html>
('document').ready(function() {
getPosts();
});
function getPosts() {
var articlePosts = $('div#content article');
$.getJSON('animeTest.json', function(data) {
$.each(data, function(key, val) {
output = "<article>";
output += "<header>";
output += "<h1>" + val.header + "</h1>";
output += "</header>";
output += "<img src='images/" + val.image + "' title='image' />";
output += "<footer>";
output += "<h1>" + val.footer + "</h1>";
output += "</footer>";
output += "</article>";
});
articlePosts.last().after(output);
});
}
You are overwriting output on each cycle
output = "<article>";
Quick fix: try appending the content inside the loop cycle too (and don't declare a global)
$.each(data, function(key, val) {
var output = "<article>";
output += "<header>";
output += "<h1>" + val.header + "</h1>";
output += "</header>";
output += "<img src='images/" + val.image + "' title='image' />";
output += "<footer>";
output += "<h1>" + val.footer + "</h1>";
output += "</footer>";
output += "</article>";
articlePosts.last().after(output);
});
BTW, I feel more comfortable operating on jQuery elements instead of concatenating html. You should try it!
var output = $('<article></article');
var header= $('<header></header');
header.append("<h1>" + val.header + "</h1>").appendTo(output);
output.append("<img src='images/" + val.image + "' title='image' />");
var footer= $ ('<footer></footer>');
footer.append("<h1>" + val.footer + "</h1>").appendTo(output);
articlePosts.last().after(output);
it saves you the pain of closing tags
You're resetting output on each iteration. Technically, you are probably only seeing the last result shown as an article in the HTML.
Instead, declare output right before $.each(), and then only ever append to it. Once you're done looping, append the entire result to your page:
function getPosts() {
var articlePosts = $('div#content article');
$.getJSON('animeTest.json', function(data) {
var output = ''; // make sure you use 'var' so it's not a global variable
$.each(data, function(key, val) {
output += "<article>";
output += "<header>";
output += "<h1>" + val.header + "</h1>";
output += "</header>";
output += "<img src='images/" + val.image + "' title='image' />";
output += "<footer>";
output += "<h1>" + val.footer + "</h1>";
output += "</footer>";
output += "</article>";
});
articlePosts.last().after(output);
});
}
Lastly, if you find yourself building HTML like this often, I would suggest looking into various HTML/JavaScript templating solutions. They would make your JavaScript code far cleaner and easier to maintain by keeping your HTML and JavaScript separate.

Add anchor point to headers?

I have a really big html-document consisting of a number of <h4> headers accompanied by a short <p> 'body'.
I need to add an anchor point (is it the correct term, btw?) to each of the headers.
I'm iterating over the headers, and adding them to a menu-ul:
headz = document.getElementsByTagName("h4");
arrayOfHeaders=[];
x = 0;
y = headz.length;
$("#menu").html("<ul>")
while (x<y){
arrayOfHeaders[x] = "<li><a href='#" + x +"'>" + headz[x].innerText + "</a></li>";
$("#menu").append(arrayOfHeaders[x])
x++;
}
$("#menu").append("</ul>")
I need a way to attach the anchor points to the headers.
Edit: To clarify - what i need is the add a name-tag to each of the -elements.
The first header should be edited from '<h4>' header'</h4>' to '<h4 name="0">'...
Without editing the html, of course.
Set ids to the if they do not have one.
headz = document.getElementsByTagName("h4");
arrayOfHeaders=[];
x = 0;
y = headz.length;
var str = "<ul>";
while (x<y){
var elem = headz[x];
var id = elem.id || "heading_" + x;
elem.id = id;
str += "<li><a href='#" + id +"'>" + elem.innerText + "</a></li>";
x++;
}
$("#menu").append( str + "</ul>");
and FYI innerText is not cross browser friendly.
jQuery solution
var str = "<ul>";
$("h4").each(
function(i){
var id = this.id || "header_" + i;
this.id=id;
str += '<li>' + this.innerHTML + '</li>';
}
);
str += "</ul>";
$("#menu").append(str);
Since you used jquery already, thought id write it all in it:
var html = '<ul>';
$('h4').each(function (index, header) {
html += '<li>' + header.html() + '</li>';
});
html += '</ul>';
$('#menu').append(html);
This might solve your problem
headz = document.getElementsByTagName("h4");
arrayOfHeaders=[];
x = 0;
y = headz.length;
var html = "<ul>";
while (x<y){
html += "<li><a href='#" + headz[x].id +"'>" + headz[x].innerText + "</a></li>";
x++;
}
$("#meny").append( html + "</ul>")
This one is similar to rissicay's answer but I think it's more concise:
var html = []; // create an empty array to store iterated html in
// loop over every heading...
$('h4').each(function(index) {
// and add it to array previously created
html.push("<li><a href='#" + index +"'>" + $(this).html() + "</a></li>");
// add name attribute to heading
$(this).attr('name', index);
});
// finally, append all to menu together with unordered list
$('#menu').append('<ul>' + html.join() + '</ul>');
Basically, try to minimize dom manipulation (.append(), .prepend(), .html()) as much as possible
I think the concept you refer to is sometimes known as an "internal link" - see here under the second section "HTML Links - The id Attribute".
Now looking at your example code you are clearly using jQuery so why not make the most of it?
$("h4").each(function() {
$("#links").append("<a href='#" + this.id + "'>link to " + this.id + "</a><br /><br />");
});
See the following fiddle - http://jsfiddle.net/r0k3t/PhrB6/
Hope that helps.

Categories

Resources