How can I duplicate a button inclusive its functions with JavaScript? - javascript

I have a button which appends some elements. I want a button which duplicates this button.
I found some articles about clone(), but I believe that's jQuery?
I can't seem to find the answer but I thought something like this:
var copybutton = create("input");
copybutton.type = "button";
copybutton.id = "copybutton" + counter;
copybutton.value = "copybutton";
addEvent(copybutton, "click", duplicatefunction);
function duplicatefunction()
{
var duplicatebutton = appendbutton.cloneNode (true);
}
Well at least that would make sense to me a little, but of course it doesn't work. How can I do this?

Given:
<div id="original">
<p>Hello World</p>
</div>
You can use something like:
var e1 = document.getElementById("original"), e2;
e2 = e1.cloneNode(true);
Set the parameter to cloneNode true if you want to recursively copy the node and its children.

Related

How to insert multi values to data-tag

I made a jquery filter function, that filtering the results by data-tags. like this:
<div class="resultblock" data-tag="ios">
<img src="images/osx.jpg" class="itemimg">
<div class="desc">
<div class="desc_text">
lorem ipsum
</div>
</div>
i just want to insert in the data-tag another tags to filter. like this:
data-tag="ios,android,windows"
How can i do that?
I am not sure I fully understand the question you are asking, but I think you could accomplish this via JS.
In your html add a script tag and then you just write some JS to edit or add html tags. Here is an example:
<script>
var para = document.createElement("p");
var node = document.createTextNode("This is new.");
para.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(para);
</script>
Now to sort the data-tag:
just add this code to your HTML file.
<div id="div1">
</div>
<script>
var tag ="ios,android,windows"; //initialize variable
var data = tag.split(","); //this makes an array of ios,andrid,windows
var i = 0;
while (i < 3){
alert(i);
var para = document.createElement("p");
var node = document.createTextNode(data[i]);
para.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(para);
i++;
}
</script>
The best way doing this is to use classes. Adding classes and removing them is much easier than other attributes. The classes should not overlap with other classes used for CSS for example. Adding a prefix to them is even better. Like this:
$(".filter-ios").hide(); // hide all ios elements
$("something").addClass("filter-windows"); // add the class windows to an element
$(".filter-ios").addClass("filter-apple"): // add the apple filter class to the ios filter class elements
$("something").hasClass("filter-samsung"); // check if an element has the filter class samsung
// ...
The classes .filter-* should be used for filtering only, they must not have any CSS attached to them, if there is already classes like that, then just change the prefix filter to something else!
I've just created a little object with two methods .add and .remove. It works like classList DOM method for adding and removing classes. If you add one value twice, it's added only once, also if you remove some not existing class, any error will occure. Hope you'll find it helpful.
var el = document.getElementById('myElem');
multiValues = {
add: function(elem,val){
if(elem.constructor.toString().search('HTML')===-1) return;
if(typeof val !=='string') return;
if(!elem.attributes['data-tag']) elem.setAttribute('data-tag');
var attr = elem.attributes['data-tag'];
var parsed = attr.value.split(',');
var isExist = parsed.some(function(a){
return a === val;
});
if(!isExist) parsed.push(val);
elem.setAttribute('data-tag',parsed.join(','));
},
remove: function(elem,val){
if(elem.constructor.toString().search('HTML')===-1) return;
if(typeof val !=='string') return;
if(!elem.attributes['data-tag']) return;
var attr = elem.attributes['data-tag'];
var parsed = attr.value.split(',');
parsed.some(function(a,b){
if(a===val){
parsed.splice(b,1);
}
elem.setAttribute('data-tag',parsed.join(','));
});
}
};
multiValues.add(el,'window');
multiValues.add(el,'window');
multiValues.add(el,'window');
multiValues.add(el,'android');
multiValues.remove(el,'a');
multiValues.remove(el,'b');
multiValues.add(el,'something');
console.log(el.attributes['data-tag'].value);
<div class="resultblock" data-tag="ios" id="myElem"></div>

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/

JavaScript - innerHTML to change more then first occurrence plus random array

I have two baffling things going on,
First: Is I’m trying to use the .innerHTML to change more than just the first occurrence.
Second: Is that I’m trying to have a random word replace the .innerHTML.
I've only been able to change the first word let alone all plus the random is a complete fail, any help would be appreciated.
Hello <p id="p1">World!</p>
Hello <p id="p1">World!</p>
Hello <p id="p1">World!</p>
<script type="text/javascript">
document.getElementById("p1").innerHTML="newWorld()";
function newWorld() {
var worlds = new Array ("Pluto!", "Mars!", "Saturn!", "Earth!", "Mercury!");
var whichWorld = Math.floor(Math.random()*worlds.length);
worlds[whichWorld]();
};
</script>
IDs in HTML documents are meant to be unique. The function getElementById will only ever return 1 element, nothing more. For groups of similar elements, you want to give them all a common class and then use getElementsByClassName (notice the plural Elements vs Element) - this function won't work with IE 8 or earlier, however, so if you need to support IE you would have to do getElementsByTagName and then filter in only those that have the class you want.
As far as the second part of the code, first you are setting the innerHTML to the actual string newWorld() not to the return value of the function (which there is none, as you are not currently returning something from within newWorld) - I think you meant to do document.getElementById("p1").innerHTML = newWorld();. Secondly, the random part of the code is correct and should be choosing a random planet each time. The end of the code is a bit puzzling, however - what exactly are you trying to do there? worlds[whichWorld] is going to be a string (Earth!, etc.) not a callable function. If worlds was an array of functions then the code would work (assuming you also returned it, since you intend to set it as the innerHTML)
In short, something like this would be the "proper" way to set all <span> elements within a parent element to a random planet:
<div id="planets">
<p>Hello <span>World!</span></p>
<p>Hello <span>World!</span></p>
<p>Hello <span>World!</span></p>
</div>
And the Javascript:
var spans = document.getElementById('planets').getElementsByTagName('span');
for(var i = 0; i < spans.length; i++) {
spans[i].innerHTML = randomWorld();
}
function randomWorld() {
var worlds = ["Pluto!", "Mars!", "Saturn!", "Earth!", "Mercury!"];
var whichWorld = Math.floor(Math.random() * worlds.length);
return worlds[whichWorld];
}
And here it is in action. You are clearly new to Javascript so I encourage you to continue to try and learn the basics of it. Eventually, however, you will want to look into libraries such as jQuery which make a lot of the tediousness of writing cross-browser Javascript go away.
According to HTML standard id must be unique, thus getElementById always return 1 element (usually the first found in the HTML.
You could write:
Hello <p class="planet">World!</p>
Hello <p class="planet">World!</p>
Hello <p class="planet">World!</p>
<script type="text/javascript">
var planets = document.getElementsByClassName("planet")
for (var i=0; i < planets.length; i++) {
planets[i].innerHTML = newWorld();
}
function newWorld() {
var worlds = new Array ("Pluto!", "Mars!", "Saturn!", "Earth!", "Mercury!");
var whichWorld = Math.floor(Math.random()*worlds.length);
return worlds[whichWorld];
}
</script>
I know jQuery is out of the scope of the question, but with a library such as jQuery (and NOT using identical ids) it would be possible to change the content of several element with one statement...
Ids in HTML are supposed to be unique. As such, the getElementById method only returns the first element with the given ID. You've got all the logic right, but you can simplify your answer a bit. Change the ids to classes and use the getElementsByClassName method like so:
Hello <span class="p1">World!</span>
Hello <span class="p1">World!</span>
Hello <span class="p1">World!</span>
<script type="text/javascript">
var worlds = ["Pluto!", "Mars!", "Saturn!", "Earth!", "Mercury!"];
var pTags = document.getElementsByClassName("p1");
for (i = 0; i < pTags.length; i++)
{
pTags[i].innerHTML = worlds[Math.floor(Math.random() * worlds.length)];
}
​</script>
DEMO
Note that the getElementsByClassName method doesn't work in IE8 or earlier. So if you want it to be backwards compatible with those browsers, you'll either need to use the getElementsByTagName and filter them manually or use jQuery.
JAVASCRIPT DEMO, WORKS ON ALL BROWSERS
JQUERY DEMO
Use a function that gives you a group of elements such as querySelectorAll or getElementsByTagName or getElementsByClassName:
Hello <p class="world">World!</p>
Hello <p class="world">World!</p>
Hello <p class="world">World!</p>
<script type="text/javascript">
var newWorld = function () {
var worlds = new Array ("Pluto!", "Mars!", "Saturn!", "Earth!", "Mercury!");
var whichWorld = Math.floor(Math.random()*worlds.length);
return worlds[whichWorld];
};
var worlds = document.getElementsByClassName("world");
for (var i=0; i < worlds.length; i++) {
worlds[i].innerHMTL = newWorld();
}
</script>
To mark multiple elements, you should use class attribute.
Multiple elements in DOM can have same value of class attribute,
but the value of id attribute should be unique.
So the example may look like:
<button id="change-world-btn">Change World</button>
<hr />
<h4>Elements with target class name:</h4>
Hello <span class="world-name">World!</span><br />
Hello <span class="world-name">World!</span><br />
Hello <span class="world-name">World!</span><br />
<hr />
<h4>Element with different class name:</h4>
Hello <span class="other-class">World!</span><br />
<script type="text/javascript">
var worlds = new Array ("Pluto!", "Mars!", "Saturn!", "Earth!", "Mercury!");
function newWorld() {
return worlds[Math.floor(Math.random() * worlds.length)];
}
elements = document.getElementsByTagName('span');
document.getElementById('change-world-btn').onclick = function() {
world = newWorld();
for(var i = 0, el; el = elements[i++];) {
if(el.className == 'world-name') {
el.innerHTML = world;
}
}
};
​</script>
Try it.
Also you can use document.getElementsByClassName function to simplify the task, but this function is not supported in IE < 9.

javascript selectors

How does one select DOM elements in javascript?
Like for example:
<div class="des">
<h1>Test</h1>
<div class="desleft">
<p>Lorem Ipsum.</p>
</div>
<div class="Right">
<button>Test</button>
</div>
</div>
Now how do i select h1? This is just a part of a bigger Page, so cannot use getElementsByTagName(), since others might get selected. Also since there might be other h1's in the document later, i cannot attach the index(body's) to above.
Is there a simple way to select, say <h1> tag which is under the classname of desleft?
I cannot use jQuery or any other libraries.
You can use this to get to your H1:
var des = document.getElementsByClassName('des')
var fc = des[0].getElementsByTagName('h1')
alert(fc[0].innerHTML)
w3.org has selectors now (http://www.w3.org/TR/selectors-api/#examples). Here are 2 different ways that worked for me on Chrome. You may want to use querySelectorAll function that returns a list.
<script type="text/javascript">
//looks for <h1> tag under <div> with className "des"
showOff1 = function() {
var x = document.querySelector(".des h1");
alert(x.innerHTML);
}
//looks for <div> tag with className "desleft" and then use previousSibling to traceback <h1> tag
showOff2 = function() {
var y = document.querySelector("div.desleft");
var z = y.previousSibling.previousSibling;
alert(z.innerHTML);
}
</script>
<body onload="showOff2();">
Use querySelectorAll
You can use querySelectorAll:
// Will return a NodeList even if there is only one element found
var heading = document.querySelectorAll('.des > h1');
heading[1].style.color = 'red'; // NodeList is similar to an array
This will return a NodeList.
or
Use querySelector to return the first element found:
var first_heading = document.querySelector('.des > h1');
first_heading.style.color = 'blue';
Commonly used with an id selector #single-header-id.
Here's a demo
getElementsByTag()
Would be a function that you can start with, and then you can filter for the DOMElements that have the class.
var h1_array = document.getElementsByTag('h1');
var h1_class_array = [];
for (var i=0, len=h1_array.length; i < len; i++) {
if (h1_array[i].className.indexOf('classname') !== -1) {
h1_class_array.push(h1_array[i]);
}
}
The .indexOf function returns -1 if the needle is not found in the haystack.
Now re-reading your question, why not just give your h1's id's ?
DOM traversal is one of javascript's glaring issues (enter jQuery).
a simple getElementById() would save you a headache, and ids on all your h1's would be much cleaner in the end than trying to formulate an algorithm to select them by other means.
If you mean to select a h1 that is before the first element of class desleft, you could always do this:
document.getElementsByClassName("desleft")[0].previousSibling.previousSibling
Example: http://jsfiddle.net/Xeon06/ZMJJk/
previousSibling needs to be called twice because of the empty text node between the two. That's why using libraries to do this stuff is really the best way to go.
var h1 = document.querySelector('.desleft').previousElementSibling;
Find element with className='desleft' using selector '.desleft'
Just move back to previous element (not to previous node!)

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