Does my javascript contain repetitive code that can be reduced? [closed] - javascript

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
I feel like there is too much repetitive code going on here. All I am doing is doing a basic regex match for a string in the URL. If a match is found, I find an li with a class (.index, .grid, .type) and add the active class. This is just for my main nav in an attempt to make it some what dynamic. However, I feel like there is a more efficient way to code this. Any help is greatly appreciated.
$( document ).ready(function() {
var myLocation = window.location;
var convertURL = new String(myLocation);
var index = /index/i;
var grid = /grid/i;
var type = /type/i;
var urlIndex = convertURL.match(index);
var urlGrid = convertURL.match(grid);
var urlType = convertURL.match(type);
if(urlIndex) {
$('.index').addClass('active');
}else if(urlGrid) {
$('.grid').addClass('active');
}else if(urlType) {
$('.type').addClass('active');
}
});

$(function(){
["index", "grid", "type"].forEach(function(term){
if(new RegExp(term, "i").test(location.href))
$("." + term).addClass("active");
});
});

$(document).ready(function () {
// use single var per function, good for minimizing and other stuff
var
i,
// new string literal, not String object
convertURL = '' + window.location,
// the array of strings keeps only the difference from the repetitive code
classes = ['index', 'grid', 'type'],
// using functions with proper arguments reduces repetitivness
matches = function (regex) {
return convertURL.match(new RegExp(regex, 'i'));
}
// var
;
// always use += instead of ++ -> makes for clear intention
for (i = 0; i < classes.length; i += 1) {
if (matches(classes[i])) {
// returning out of this function stops iteration
return $('.' + classes[i]).addClass('active');
}
}
});

Related

Javascript: Expected Identifier [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I am creating an HTML document and using javascript to create an image element.
Here is my code (create is already defined):
create=document.createElement("img");
create.src = 'data/1.png';
create.alt = 'image1';
create.style.magin = '1px';
eval("create.id = 'image" + count + "'");
create.class = 'block'; // line that breaks the code
document.body.appendChild(create);
I don't know what's going wrong here, but it's probably something obvious. Does anyone have any ideas?
Here's your code working with the variable count defined, an example image and the correct way to add a class to the element:
var count = 1;
create=document.createElement("img");
create.src = 'http://via.placeholder.com/350x150'; // 'data/1.png';
create.alt = 'image1';
create.style.magin = '1px';
eval("create.id = 'image" + count + "'");
create.classList.add('block');
document.body.appendChild(create);
As no necessity for eval and you can use classList for add a class.
for(var count = 1; count < 10; count++){
create=document.createElement("img");
create.src = 'data/1.png';
create.alt = 'image' + count;
create.style.magin = '1px';
create.id = 'image' + count;
create.classList.add('block');
document.body.appendChild(create);
}
You also can use create.style.display = 'block'; if you want just add a style.
More examples how set attributes and styles here

createElement within for loop [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 years ago.
Improve this question
I want to make an element 50 times within a for loop. My code is below:
function pGenerate() {
for (i, i <= 50; i++;) {
var newP = document.createElement("p");
var pText = document.createTextNode("sample paragraph");
newP.appendChild(pText);
var contentSection = document.getElementById("content");
document.body.insertBefore(newP, contentSection);
}
}
The expected result is that it generates 50 <p> tags with "sample content inside of them. The actual result is well...nothing. https://jsfiddle.net/2L8reked/1/
My thought process behind the code I wrote this code is as follows: I basically have a loop set to cycle 50 times. for each cycle, I want to create a p tag, along with create a text node with the content "sample paragraph." In the next step, I grab the div by it's id, #content, and I then attempt to populate the area using insertBefore.
My error here seems to be how I use insertBefore. Looking this up on MDN, it's definition is "inserts the specified node before the reference node as a child of the current node." https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore
With that definition in mind - I'm using this with the understanding as of now that I'm inserting (or attempting to) the p tags as a child of #content. Should I be using a different method? Am I misunderstanding how this works?
I also tried an innerHTML approach, seen here: https://jsfiddle.net/0e1ej9sk/1/
which method is best suited for what I'm trying to do?
In the first example what is the flaw behind my logic of the use of insertBefore?
You have 3 syntax errors.
Change i, in for loop to 1=1; then remove the last ; where i++; to i++
function pGenerate() {
for (i=1; i <= 50; i++) {
var newP = document.createElement("p");
var pText = document.createTextNode("sample paragraph");
newP.appendChild(pText);
var contentSection = document.getElementById("content");
document.body.insertBefore(newP, contentSection);
}
}
window.onload = function() {
pGenerate();
}
<div id="content"></div>
You need to initialize i at 1, and properly separate all parts of the for statement with semi-colons, like this:
function pGenerate() {
for (var i = 1; i <= 50; i++) {
var newP = document.createElement("p");
var pText = document.createTextNode("sample paragraph (i=" + i + ")");
newP.appendChild(pText);
var contentSection = document.getElementById("content");
document.body.insertBefore(newP, contentSection);
}
}
pGenerate();
<div id="content"></div>
you can do this
function pGenerate() {
for (i=1; i <= 50; i++) {
var newP = document.createElement("p");
var pText = document.createTextNode("sample paragraph");
newP.appendChild(pText);
var contentSection = document.getElementById("content");
document.body.insertBefore(newP, contentSection);
}
}
document.ready(pGenerate);

Compare input to every id and output the closest matching one [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I'm making basic search on my website. When you type into the search it automatically compares the input against every element-id in the document. When it finds a match it scrolls to the matched element. As of now the search works only when you input the exact id (excluding case-sensitivity and spaces).
Here is my JQuery code:
$('#search-box').focus(function() {
$('#search-box').keyup(function () {
var x = $('#search-box').val().replace(/\s+/g, '').toLowerCase();
if ($("#" + x).length !== 0) {
navbarHeight = $('#fixed-navbar').height();
$('html, body').animate({scrollTop:$('#'+x).position().top - window.navbarHeight}, 500);
}
});
});
I think, I've tried everything starting from .match() to using plugins like List.js.
Is there a way to compare inputed text to id's and output the first matching one? Tolerance modifier would be neat but not required.
My solution:
// Searches automatically for first matching id
var idArray = $("div[id^='x-']") // find spans with ID attribute
.map(function() { return this.id; })// convert to set of IDs
.get(); // convert to instance of Array (optional)
navbarHeight = $('#fixed-navbar').height();
console.log(idArray);
$('#search-box').keyup(function () {
for (var i=0; i<idArray.length; i++) {
var input = $('#search-box').val().replace(/\s+/g, '').toLowerCase();
matched = idArray[i].match(new RegExp(input));
if (matched !== null) {
$('html, body').animate({scrollTop:$('#'+ idArray[i]).position().top - window.navbarHeight});
console.log('Matched part: ' + matched);
break;
};
if (matched == undefined) {
matched = [];
matched.length = 0;
};
};
});
Working JSFiddle.
(thx for help guys /s)
Final thoughts:
I didn't add the tolerance variable but it's easy enough (compared to this IMO).
Also, I may add so that it stats to search only from the beginning of the id (because people usually start typing the beginning of the word) but then the "search anywhere in the name" functionality won't work.
Edit: Finally managed to make it work the way I asked to. Code almost rewritten and updated.

How do I create a list of quotes in my html from javascript objects? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking us to recommend or find a book, tool, software library, tutorial or other off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it.
Closed 8 years ago.
Improve this question
*A Jsfiddle would be appreciated, thanks!
This is a sample of what I've been given in a js document:
var comments = [
{"name":"John","comment":"Text","timestamp":69379200},
{"name":"Ronny","comment":"Text","timestamp":1007683200},
{"name":"Darrel","comment":"Text","timestamp":172281600}
];
How do I load that into my preexisting unordered list as list items? Ideally in this sort of a format (including turning the unix timestamps into this format):
<ul class="testimonials">
<li>
<blockquote>"Text"</blockquote>
<cite>-John, 8/23/2014</cite>
</li>
<li>
<blockquote>"Text"</blockquote>
<cite>-Ronny, 8/23/2014</cite>
</li>
<li>
<blockquote>"Text"</blockquote>
<cite>-Darrel, 8/23/2014</cite>
</li>
</ul>
I'm new to loading javascript into my html, so if anyone can help me out and explain, I'd really appreciate it! Thanks!
Try something like this:
// the parent element
var ulElement = document.createElement("ul");
ulElement.setAttribute("class", "testimonials");
// iterate through the array
for ( var i = 0 ; i < comments.length ; i++ ) {
// extract data from JavaScript
var currentObj = comments[i];
var currentName = currentObj.name;
var currentComment = currentObj.comment;
var currentTimestamp = currentObj.timestamp;
// create child nodes for the parent
var liElement = document.createElement("li");
// blockquote
var blockquoteElement = document.createElement("blockquote");
var t1 = document.createTextNode(currentComment);
blockquoteElement.appendChild(t1);
// cite
var citeElement = document.createElement("cite");
var d = new Date(currentTimestamp*1000);
var formattedDate = d.getMonth()+ "/" + d.getDate() + "/" + d.getFullYear()
var t2 = document.createTextNode(currentName + ", " + formattedDate);
citeElement.appendChild(t2);
// add children for li
liElement.appendChild(blockquoteElement);
liElement.appendChild(citeElement);
// add child nodes to parent
ulElement.appendChild(liElement);
}
Here you can see a fiddle
Here is something to get you started:
var comments = [
{"name":"John","comment":"Text","timestamp":69379200},
{"name":"Ronny","comment":"Text2","timestamp":1007683200},
{"name":"Darrel","comment":"Text3","timestamp":172281600}
];
var feed = document.getElementById('feed'); // get our UL element
var output = ""; // define output string variable
for (var i = 0; i < comments.length; i++) { // start the loop
output += '<li><blockquote>' + //
comments[i].comment + // build the output
'</blockquote><cite>-' + // on each iteration
comments[i].name + ', ' + // and append it
comments[i].timestamp + // to its previous value
'</cite></li>'; //
}
feed.innerHTML = output; // after the loop is done,
// set the contents of our UL
// element to the output we just built
See it in action here: http://jsfiddle.net/4aoh682q/1/
(note: I didn't convert the timestamp into formatted date)
The simplest way is to use some templating framework like Mustache or even the simple mechanism Underscore.js uses and be done with it.
One big problem with Shomz's answer (as of this writing) is it doesn't handle html injection issues.
The answer from curiosu would seem to handle that from first reading but it could possibly be better; it's better to minimize interaction with the DOM to avoid causing issues with the rendering engine. His doesn't necessarily do this―it is likely only a problem if the ul element has already been added. But see how verbose this DOM code is? Creating elements using the DOM apis can be quite useful, but writing the code is so tedious!
If you only need this functionality to create lists, it would actually be better not to use the templating framework as that code is just extra crap to bog down the page, but if you are using more than one list thing and you need extra flexibility to quickly modify what classes elements need, etc, it is hard to beat the usefulness of a templating framework.
Edit:
I will add that it's not hard to fix the encoding issues in Shomz's answer, and performance issues, if there are any, could be fixed by using an array, and joining afterwards.
Just add a proper htmlEncode
function htmlEncode( html ) {
return document.createElement( 'a' ).appendChild(
document.createTextNode( html ) ).parentNode.innerHTML;
}
and then
var feed = document.getElementById('feed'); // get our UL element
var output = []; // define output string variable
for (var i = 0; i < comments.length; i++) { // start the loop
output.push('<li><blockquote>' + //
htmlEncode(comments[i].comment) + // build the output
'</blockquote><cite>-' + // on each iteration
htmlEncode(comments[i].name) + ', ' + // and append it
comments[i].timestamp + // to its previous value
'</cite></li>'); //
}
feed.innerHTML = output.join(""); // after the loop is done,
// set the contents of our UL
// element to the output we just built
http://jsfiddle.net/4aoh682q/6/

Is there any way to optimise this code? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I have a piece of code which will invert all the checkboxes on my form. I have multiple elements (not just checkboxes but also <input type='text'>'s) in it. The reason I need it to be optimised is because it takes about two to three seconds to select all the checkboxes (275 right now).
Here's my code:
function FormInverse() {
var iCheckbox = 1; // Because there are multiple input elements, we need to distinquish the input element ID and the row id
var FormLength = document.FormFacturen.elements.length;
for (i=0; i < FormLength; i++) {
var FormElementType = document.FormFacturen.elements[i].type;
if (FormElementType == "checkbox") {
var Elements = document.getElementsByClassName('row' + iCheckbox); // Alle elementen in de array zetten
var iNumElements = Elements.length;
for (iElement=0; iElement < iNumElements; iElement++) {
if (document.FormFacturen[i].checked == true) {
Elements[iElement].className = "invoice-tr-standard row" + iCheckbox;
} else {
Elements[iElement].className = "invoice-tr-clicked row" + iCheckbox;
}
}
iCheckbox++;
document.FormFacturen[i].checked = !document.FormFacturen[i].checked;
}
}
}
And here is the document.getElementsByClassName function:
document.getElementsByClassName = function(cl) {
var retnode = [];
var myclass = new RegExp('\\b'+cl+'\\b');
var elem = document.getElementsByTagName('*');
for (var i = 0; i < elem.length; i++) {
var classes = elem[i].className;
if (myclass.test(classes)) retnode.push(elem[i]);
}
return retnode;
};
I would suggest using jQuery as well.
Try this:
Add a reference to jQuery:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" type="text/javascript" language="JavaScript"></script>
Use this code:
$(':checkbox').each( function() {
$(this).attr('checked', !$(this).attr('checked'));
});
Edited:
Or use this to change the classes as well:
$(':checkbox').each(function() {
var checked = $(this).attr('checked');
if (checked) {
$(this).attr('checked', false);
$(this).addClass('invoice-tr-clicked');
$(this).removeClass('invoice-tr-standard');
}
else {
$(this).attr('checked', true);
$(this).addClass('invoice-tr-standard');
$(this).removeClass('invoice-tr-clicked');
}
});
Final version:
$('#FormFacturen :checkbox').each(function() {
var checked = $(this).attr('checked');
if (checked) {
$(this).attr('checked', false);
$(this).parents('tr').addClass('invoice-tr-clicked');
$(this).parents('tr').removeClass('invoice-tr-standard');
}
else {
$(this).attr('checked', true);
$(this).parents('tr').addClass('invoice-tr-standard');
$(this).parents('tr').removeClass('invoice-tr-clicked');
}
});
Each call to getElementsByClassName is expensive, and it is being called on each pass of your for loop.
In addition to #Geoff's suggestion, you could call document.getElementsByTagName('input'); just once, instead of each time getElementsByClassName is called and cache the result for use within your loop.
That would require making a small modification to your getElementsByClassName function whereby it accepts an array of elements to search through.
document.getElementsByClassName = function(cl, eles) {
var retnode = [];
var myclass = new RegExp('\\b'+cl+'\\b');
var len = eles.length;
for (var i = 0; i < len; i++) {
var classes = eles[i].className;
if (myclass.test(classes)) retnode.push(eles[i]);
}
return retnode;
};
function FormInverse() {
// cache all inputs
var inputs = document.getElementsByTagName("input");
...
// later
var Elements = document.getElementsByClassName('row' + iCheckbox, inputs);
You should look into a library like JQuery. It will handle this kind of thing well.
There are a lot of little things you can do to improve your code though. First thing I notice is that your getElementsByClassName function is looping through ALL elements on your page every time you call it. You could change this line:
var elem = document.getElementsByTagName('*');
to just get the input elements:
var elem = document.getElementsByTagName('input');
I am pretty much sure the bottleneck here is the getElementsByClassName function, the browser needs to re-scan the whole html each time to find your element. I suggest you give your elements a unique id id="row1", id="row2", ... instead of a unique class name and use getElementById which is much faster.
var Elements = document.getElementsById('row' + iCheckbox);

Categories

Resources