How to improve jQuery code - javascript

I have the syntax below. I was wondering if this part: $($(this).parent().siblings('div')[0]) could be writen more elegantly by accessing a jQuery object directly without the need to use $(); again.
I used .parent().siblings and didn't use the class of div because I want to reuse the code somewhere where the classes are different.
$('textarea').click(function(){
$($(this).parent().siblings('div')[0]).html('<span>140</span>');
$($(this).parent().siblings('div')[1]).html('<span>Reply</span>');
});
<div class="post_area2">
<div class="wrap_area2 left">
<textarea></textarea>
</div>
<div class="word_c left"></div>
<div class="submit left"></div>
</div>

You can use .eq() method.
$('textarea').click(function(){
$(this).parent().siblings('div')
.eq(0).html('<span>140</span>').end()
.eq(1).html('<span>Reply</span>');
});

Try
$('textarea').click(function(){
$(this).parent().next().html('<span>140</span>')
.next().html('<span>Reply</span>');
});
http://jsfiddle.net/rVfJ4/

I agree with sweetamylase's answer.
That code should work. Because it is using native javascript, I think it is good for performance.
Or use class name for determinate div:
$('textarea').click(function(){
var parentDiv = $(this).parents('div.post_area2'); // avoid to use $(this) multi time in this function
parentDiv.find('div.word_c').html('<span>140</span>');
parentDiv.find('div.submit').html('<span>Reply</span>');
});
That will work exactly even you add new another div.
Don't use 'eq()' if you have another solution.
I'm sorry, I'm not enough reputation for voting.

I would re-write it as such:
$('textarea').click(function(){
var divContainer = $(this).parent().siblings('div');
divContainer[0].innerHTML = '<span>140</span>';
divContainer[1].innerHTML = '<span>Reply</span>';
});
You can use native attribute innerHTML to set the contents of the DOM element, it is equivalent to using .html() minus the requirement of invoking the jQuery object.
Also, it depends if your coding style likes to do chaining because that's really easily done with jQuery, but can be difficult to read when the line becomes long.

You should give the other divs extra classes to represent what they mean.
$('textarea').click(function(){
$(this).parents('form').children('.hide-until-using-form').show();
});
This creates a highly reusable function that doesn't depend on how many siblings are involved, what the text of the button is (Post? Edit?), etc.

There is infinite ways to do it,
You can think a bit out of the box, i'm not sure that the latest version of jquery optimize the access to elements, if i'm wrong feel free to make me sorry on it.
But here are a few ways to do it:
var parentSelector = $(this).parent().parent();
var parentSelector = $(this).parents('#uniqueId');
var currentId = this.id;
var childrenSelector = parentSelector.children('div[id!="' + currentId + '"'];
var one = $(childrenSelector.get(0));
var two = $(childrenSelector.get(1));
A simple way to optimize the access to elements is to wrap/create new function that save reference to DOM elements, there is some issues that need to be consider but you can make a nice dom-cache library.

Perhaps like this
$('textarea').click(function () {
var parentSiblings = $(this).parent().siblings('div');
$(parentSiblings[0]).html('<span>140</span>');
$(parentSiblings[1]).html('<span>Reply</span>');
});
Or
$('textarea').click(function () {
var parentSiblings = $($(this).parent().siblings('div'));
parentSiblings.eq(0).html('<span>140</span>');
parentSiblings.eq(1).html('<span>Reply</span>');
});
Others may see using vanilla javascript more elegant.
function empty(element) {
"use strict";
while (element.hasChildNodes()) {
element.removeChild(element.lastChild);
}
}
function addEvent(nodeList, type, callBack) {
"use strict";
var length = nodeList.length,
i = 0;
while (i < length) {
nodeList[i].addEventListener(type, callBack, false);
i += 1;
}
}
addEvent(document.getElementsByTagName("textarea"), "click", function (evt) {
"use strict";
var divContainer = evt.target.parentNode.parentNode.getElementsByTagName("div"),
span;
empty(divContainer[1]);
span = document.createElement("span");
span.textContent = "140";
divContainer[1].appendChild(span);
empty(divContainer[2]);
span = document.createElement("span");
span.textContent = "Reply";
divContainer[2].appendChild(span);
});
These and others are available on jsfiddle
I guess it depends on how exactly you define more elegant. Sometimes readability is more important, perhaps not including ant 3rd party libraries and using vanilla javascript.

Related

js How to add href + text onclick

I need to pass (using javascript) text inside span to href
<div class='tableCell'><span>information</span></div>
<div class='tableCell'><span>contact</span></div>
<div class='tableCell'><span>about</span></div>
for example when i click to about link must be example.com/tag/about/
Here is my Answer. I'm using Javascript to manipulate the DOM to add a new element with the href equal to the inner text within the span element.
I hope you find this answer helpful.
Thanks.
var spans = document.getElementsByTagName('span')
var baseUrl = 'http://example.com/tag/'
for(var i=0; i<spans.length; i++)
{
var curElement = spans[i];
var parent = curElement.parentElement;
var newAElement = document.createElement('a');
var path = baseUrl+curElement.innerHTML;
newAElement.setAttribute('href', path);
newAElement.appendChild(curElement);
parent.appendChild(newAElement)
}
DEMO
The simplest way:
$( "span" ).click(function() {
var link = 'http://yousite.com/tag/'+ $(this).text().replace(/ /, "-")+"/";
window.location.href= link.toLowerCase();
});
DEMO
http://codepen.io/tuga/pen/yNyYPM
$(".tableCell span").click(function() {
var link = $(this).text(), // will provide "about"
href = "http://example.com/tag/"+link; // append to source url
window.location.href=href; // navigate to the page
});
You can try the above code
You do not have links but span in your html. However, you can get build the href you want and assign it to an existing link:
$('div.tableCell').click(function(){
var href = 'example.com/tag/' + $(this).find('span').text();
})
Lets work with pure javascript, I know you want to use jQuery but I am really sure too many people can't do this without looking in to web with pure javascript. So here is a good way.
You can follow it from jsFiddle
var objectList = document.getElementsByClassName("tableCell");
for(var x = 0; x < objectList.length; x++){
objectList[x].addEventListener('click', function(){
top.location.href = "example.com/tag/" + this.childNodes[0].innerHTML;
});
}
Lets work on the code,
var objectList = document.getElementsByClassName("tableCell");
now we have all element with the class tableCell. This is better than $(".tableCell") in too many cases.
Now objectList[x].addEventListener('click', function(){}); using this method we added events to each object.
top.location.href = "example.com/tag/" + this.childNodes[0].innerHTML; with this line if somebody clicks to our element with class: We will change the link to his first child node's text.
I hope it is useful, try to work with pure js if you want to improve your self.
Your Method
If you always are going to have the url start with something you can do something like this. The way it is set up is...
prefix + THE SPANS TEXT + suffix
spaces in THE SPANS TEXT will be converted to -
var prefix = 'http://example.com/tag/',
suffix = '/';
$('span').click(function () {
window.location.href = prefix + $(this).text().replace(' ', '-').trim().toLowerCase() + suffix;
//An example is: "http://example.com/tag/about-us/"
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='tableCell'><span>Information</span></div>
<div class='tableCell'><span>Contact</span></div>
<div class='tableCell'><span>About</span></div>
You can adjust this easily so if you want it to end in .html instead of /, you can change the suffix. This method will also allow you to make the spans have capitalized words and spaces.
JSBIN

How to append elements to the parent elements extracted by getElementsByClassName?

Below is my JSP code,
<%
while(resultSet1.next()){
out.println("<p class='comm'>");
out.println(resultSet1.getString("answer_content"));
out.println("</p>");
}
%>
Below is the script I have used,
<script>
$( document ).ready(function() {
var par = document.getElementsByClassName("comm");
var insert = document.createElement("form");
insert.setAttribute("action","ForumSubmitCommentController");
var text = document.createElement("input");
text.setAttribute("type","text");
text.setAttribute("name","comm_text");
text.setAttribute("id","comm_text");
insert.appendChild(text);
var comm_submit = document.createElement("input");
comm_submit.setAttribute("type","submit");
comm_submit.setAttribute("value","Comment");
insert.appendChild(comm_submit);
par.appendChild(insert);
});
</script>
I'am expecting to get a form attached to all the 'p' elements with "class='comm'" but I'm getting none. So can anyone point out what I'm doing wrong?
Thanks in advance.
because par is an array, so doesn't have appendChild method
$(document).ready(function () {
$('.comm').each(function () {
var insert = document.createElement("form");
insert.setAttribute("action", "ForumSubmitCommentController");
var text = document.createElement("input");
text.setAttribute("type", "text");
text.setAttribute("name", "comm_text");
text.setAttribute("id", "comm_text");
insert.appendChild(text);
var comm_submit = document.createElement("input");
comm_submit.setAttribute("type", "submit");
comm_submit.setAttribute("value", "Comment");
insert.appendChild(comm_submit);
this.appendChild(insert);
})
});
Demo: Fiddle
But a easier way to do it is to use
$(document).ready(function () {
var form = '<form action="ForumSubmitCommentController"><input type="text" name="comm_text" id="comm_text"><input type="submit" value="Comment"></form>';
$('.comm').append(form)
});
Demo: Fiddle
This kind of DOM manipulations is very basic stuff when you use some library (like jQuery) but sometimes can be hard or at least verbose with plain old DOM API.
For example document.getElementsByClassName returns HTMLCollection. It is array-like collection of elements found. You need to traverse it in some way to put your form to all of the elements.
For example:
nodesList = document.getElementsByClassName("helloworld");
for(var i = 0; i < nodeList.length; i++) {
var node = nodeList[i];
// create form etc...
node.appendChild(form);
}
Notice that HTMLCollection does not even provide forEach method - we have to use plain for-loop or convert it to Array first (e.g. by using hacks like this one). And you must create your form node (or use cloneNode) before every appendChild, because each DOM node is unique and appendChild only moves it to desire location.
jQuery and other libraries do that behind the scene, hiding complexities and making your code more readable. I suggest you to learn DOM API only to get the understanding about how things really work. In real projects just stick with jQuery, learn it and use it for all manipulations.

Javascript - remove button and parent

Hi I am just learning Javascript and after following some tutorials I thought it would be nice to practise some Javascript by making stuff.
So now I am trying to make a very easy to-do-list. Just for practise, but I get stuck.
I managed to add items with a remove-button to an UL with JS. But, BUT:
How do I make it so; when you click on the removeMe button, that only that Li will be removed?
What should I use?
Here's my code:
var buttonAdd = document.getElementById('but1');
var buttonRemove = document.getElementById('but2');
var ul = document.getElementById('myUl');
function addLi() {
var newLi = document.createElement('li');
var removeThis = document.createElement('button');
var textInput = document.getElementById('inputText').value;
if(textInput === ""){
alert('Add text');
}else{
newLi.innerHTML = textInput;
newLi.appendChild(removeThis);
removeThis.innerHTML = "Remove me";
removeThis.setAttribute("onClick", "removeMe(this);");
ul.appendChild(newLi);
}
}
buttonAdd.onclick = function() {
addLi();
};
buttonRemove.onclick = function() {
ul.innerHTML = "";
};
function removeMe(item){
//get called when clicked on the remove button
}
and my HTML:
<body>
<ul id="myUl"></ul>
<input id="inputText" type="text"><br />
<button id="but1">Add stuff</button><br />
<button id="but2">Remove all</button>
</body>
Thanks
The function remove() is a brand new DOM 4 method and not very widely supported yet. The clunky, but bulletproof way would be:
function removeMe(item){
item.parentElement.parentElement.removeChild(item.parentElement);
}
or with a bit more elegance:
function removeMe(item){
var parent = item.parentElement;
parent.parentElement.removeChild(parent);
}
http://jsfiddle.net/BtbR4/
Also be careful with this:
removeThis.setAttribute("onClick", "removeMe(this);");
Handing a function reference as a string is always a bad idea for several reasons (eval'ing the string, messing up the scope). There are several better options:
removeThis.onclick = removeMe;
or if you need to hand over parameters
removeThis.onclick = function(){removeMe(your,parameters)};
The best option however is to attach eventhandlers always like this:
Element.addEventListener("type-of-event",functionReference);
You just need to remove the parent node (the li), as I've shown using jsbin.
function removeMe(item){
item.parentNode.remove();
}
Please note Blue Skies's comment that this may not work across all browsers, an alternative is:
var par = item.parentNode; par.parentNode.removeChild(par);
a cleaner way to do things is to add
removeThis.onclick = removeMe;
and
function removeMe(mouseEvent){
this.parentNode.remove();
}
This is consistent with how you add the other onclick functions in your code. Since you said you are learning js, it is a good idea to learn how events and functions work. So, the take away from this is that the 'this' of a function that is attached to an object is the object itself (the removeThis object in this case), and event handlers give you access to the event that invoked them (mouseEvent) in the argument list.
JSfiddle: http://jsfiddle.net/QT4E3/

How to surround element with div

How to surround element with div tag in dojo?
<button>Testing</button>
:
<div>
<button>Testing</button>
</div>
<div>Testing <span>something</span></div>
:
<div>
<div>Testing <span>something</span></div>
</div>
Finally I found answer
Surrounding
var node = domConstruct.create("div");
dojo.addClass(node,"container");
var refNode = dom.byId("refNode");
var tagName = refNode.tagName.toLowerCase();
node.innerHTML="<"+tagName+">"+refNode.innerHTML+"</"+tagName+">";
domConstruct.place(node, refNode,"before");
domConstruct.destroy(refNode);
Its pretty simple
require(["dojo/dom-construct"], function(domConstruct){
var n = domConstruct.create("div", { innerHTML: "Testing <span>something</span>" });
});
read all about it here
How about this :
var refNode = dom.byId("refNode");
// make the new div, with the correct class, directly after the node to be wrapped
var node = domConstruct.create("div", {"class":"container"}, refNode, "after");
// move the refNode inside our wrapping node
domContruct.place(refNode, node);
A quick and dirty approach looks like this:
element.outerHTML = '<div>' + element.outerHTML + '</div>';
No need for any libraries. Note, this will create a new object under the hood, so you have to retrieve element again to get the surrounding element, in case you need it afterwards.
Overall, it's handy, because you do not have to remove the old element and insert the new one.
I also came up with a similar approach to replace the tag name and preserve attributes, which might be interesting for one or another.
I don't know how it was in 2013, but these days, dojo's NodeList-manipulate functionality allows you to do it quite easily.
Given:
<b>one</b>
<b>two</b>
Use:
require(["dojo/query", "dojo/NodeList-manipulate"], function(query){
query("b").wrap("<div><span></span></div>");
});
Output:
<div><span><b>one</b></span></div>
<div><span><b>two</b></span></div>
This example is take from the documentation here.

Javascript DOM howto?

I am a javascript noob.
I would like to select the second 'p' element of the div.box.
How do I do this?
Thanks a lot!
Tom
To get second p element of div with class box you'd do this:
var paragraph = null;
var divs = document.findElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
var div = divs[i];
if (div.class == 'box') {
var paragraphs = div.getElementsByTagName('p');
if (paragraphs.length > 1)
paragraph = paragraphs[1];
break;
}
}
The paragraph would then be in the paragraph variable (or null if it wasn't found).
However you can do this much easier with a library such as jQuery:
var paragraph = $('div.box p:eq(1)');
Without using jQuery, the basic method would be to attach an unique ID to your Dom element
<p id="second_p_elmt"> [...] </p>
and then accessing it through the getElementById() method:
<script ...>
var second_p_elmt = document.getElementById('second_p_elmt');
</script>
<script type="text/javascript">
var boxElem = document.getElementById('box'),
pElems = boxElem.getElementsByTagName('p'),
whatYouWant = pElems[1]; // [1] is the second element in the response from getElementsByTagName
</script>
You have several options. As stated above, you could use one of the excellent frameworks, like jQuery or prototype. Or you give the <p/> an ID, that you can use simply with document.getElementById().
Then, as reko_t pointed out, without the above, you must write a lengthy DOM traversing code (which is preferable, if you don't use JS frameworks elsewhere, over embedding them only for this task).
In the most recent browsers (namely, IE>=8, FF>=3.5, recent Opera and Safari > 3) you can also use this simple snippet:
var p = document.querySelectorAll("div.box p");

Categories

Resources