this looks simple enough but I just can't get it to work. I could add DOM elements but I just can't remove them when using an array.
<script language="javascript">
fields = 0;
count = 0;
function addInput() {
if (fields != 10) {
var htmlText = "<input type='search' value='' name='field[]' />";
var remButton = "<input type='button' value='del' onclick='remove()' />";
var newElement = document.createElement('div');
newElement.id = 'SomeID'+fields;
newElement.innerHTML = htmlText + remButton + newElement.id;
var fieldsArea = document.getElementById('text');
fieldsArea.appendChild(newElement);
fields += 1;
} else {
...
}
count++;
}
// NEED HELP FROM HERE PLEASE
// You don't need to Loop, just get the button's id and remove that entire 'SomeID'
function remove() {
fieldsArea = document.getElementById('text');
fieldsArea.removeChild(SomeID1); <-----------------------THIS WORKS!
fieldsArea.removeChild(SomeID+count); <------------------THIS JUST WOULDN'T
count--;
}
</script>
In the remove function, writing SomeID1 works and delete the first added element but when I try to use a 'count', I just can't delete my 'elements'.
Any help would be most appreciated.
Thank you!
You have to get a reference to the element first. Currently you are passing an undefined variable SomeID to the function.
E.g.:
var element = document.getElementById('SomeID' + fields);
// or starting by zero: var element = document.getElementById('SomeID0');
element.parentNode.removeChild(element);
If you want to remove the div for which the button was clicked, you have to pass a reference to the corresponding div to the remove function.
'<input type="button" value="del" onclick="remove(this.parentNode)" />';
this will refer to the button and as it is a child of the div, this.parentNode refers to that div.
You also have to change your function to accept the element that should be removed:
function remove(element) {
element.parentNode.removeChild(element);
count--;
}
You probably also have to update fields, but I'm not sure how your code is supposed to work.
If you want to remove all of them you have to loop:
for(;fields--;) {
var element = document.getElementById('SomeID' + fields);
element.parentNode.removeChild(element);
}
Also have a look at the documentation of removeChild.
The removeChild needs a node (DOM element) as parameter. In this case
fieldsArea.removeChild(SomeID+count);
you could for example pass the node this way
fieldsArea.removeChild(document.getElementById('SomeID'+count));
Related
I am programmatically generating some HTML, and trying to add a listener for a change event the elements.
This works fine for the first object, but as soon as I add the second object the first one stops firing the event.
In the code example below you'll see the updateLabel function only fires for the last object created. I need it to fire for all of the objects.
I have tried with .onchange, and with an event listener, but get the same results.
Any help much appreciated.
<html>
<body>
<div id="main">
<!--this is where all the generated HTML goes -->
</div>
</body>
<script>
mainDomElement = document.querySelector("#main");
for (var count = 0; count < 4; count++)
{
var labelId = 'Label' + count;
newHTML = '<input class="accordionLabel" type="text" id="' + labelId + '" value="' + labelId + '"/>'
currentHTML = mainDomElement.innerHTML
mainDomElement.innerHTML = newHTML + currentHTML
labelDomObj = document.querySelector('#' + labelId);
//labelDomObj.addEventListener("change", updateLabel);
labelDomObj.onchange = function(event){updateLabel(event)}
}
function updateLabel(event)
{
alert(event.target.value);
}
</script>
</html>
It may be best to take a different approach when creating and adding DOM elements. Try this.
for (var count = 0; count < 4; count++)
{
var labelId = 'Label' + count,
newHTML = document.createElement('input');
newHTML.type = 'text';
newHTML.value = labelId;
newHTML.id = labelId;
newHTML.addEventListener('onchange', updateLabel, false);
mainDomElement.appendChild(newHTML);
}
your code explanation
// this takes the main DOM element and stores a copy of it in the variable.
currentHTML = mainDomElement.innerHTML
/*
This is taking the innerHTML property of the main DOM element. It is then
trying to concatenate the newly created DOM to that stored in the mainDomElement
variable. I don’t think this is what you want.
*/
mainDomElement.innerHTML = newHTML + currentHTML
// this is trying to select an element from the DOM that does not exist yet.
labelDomObj = document.querySelector('#' + labelId);
// This is trying to add an event listener to an element that does not exist.
labelDomObj.onchange = function(event){updateLabel(event)}
You are also missing sim icons from your variable declarations.
This looks like an issue with closures, where initializing var count = 0 within the for loop ultimately results in only the last value getting bound to the event handler.
I believe moving the initialization outside of the loop will fix your issue. Also, ES6 introduced the let keyword that scopes the variable in the way you are expecting:
for (let count = 0; count < 4; count++) { }
See this excellent introduction to javascript closures for more information.
I have some <div> in which I all the time add new objects.
These objects are assigned with listeners.
The problem is that when I add these new objects using .innerHTML, the previous listeners get lost.
Is it possible to create a JS string which represents an HTML object, and to append it as a child without .innerHTML += ... ?
I'll give an example:
var line_num = 0;
function addTextLine(line) {
var lineId = "line_" + line_num;
var lineHtml = "<p id = '" + lineId + "'>" + line + "</p>";
document.getElementById("some_div_id").innerHTML += lineHtml;
document.getElementById(line_id).addEventListener("click", function() {
alert("hello");
});
line_num += 1;
}
The modification of innerHTML of some_dive_id, removes the event listeners of the old <p> objects.
So - is it possible to convert the <p> HTML string into an object, and thus to append it to the some_div_id without modifying its .innerHTML ?
Your problem is that innerHtml erases then recreates the current DOM node; that's why you lose you event listeners.
you can insert your html with insertAdjacentHtml
document.getElementById("some_div_id").insertAdjacentHTML('afterbegin', lineHtml );
the afterbegin parameter assure the inserted html will be a child of your current node.
Look for more infos here: Element.insertAdjacentHTML()
Create the element and append it
var p = document.createElement("p");
p.innerHTML = line;
p.id = line_id; // or p.setAttribute("id", line_id);
p.addEventListener("click", function(){ });
document.getElementById("foo").appendChild(p);
Another option can be to create an element, and set the innerHTML and read the element from there. (First option is better)
var div = document.createElement("div");
div.innerHTML = lineHtml;
//now you can either select the children and append it or append the div.
use element.appendChild().
Your code is not working because everytime you use innerHtml += 'Something' you are removing anything inside that particular element and inserting old content with added string.
Instead you can create element with function and append it to parent element.
Rewriting your code should be:
var line_num = 0;
function addTextLine(line) {
var line = document.createElement('p');
line.id = "line_" + line_num;
line.textContent = line;
line.addEventListener("click", function() {
alert("hello");
});
document.getElementById("some_div_id").appendChild(line);
line_num += 1;
}
I am working on a personal project in Javascript to allow people to create a table of "dream plays" in Scrabble. Here is the link: http://psyadam.neoclaw.net/tables8.html
I am currently trying to allow the user to edit a dream play.
Here is my code:
function editRow(e)
{
var eventEl = e.srcElement || e.target,
parent = eventEl.parentNode
parent = parent.parentNode
var test = $(parent.cells[0]).text()
$('tr').each(function(){
$(this).children("td:contains(test)").each(
function()
{
pageEnd.innerHTML += "success"
$(this).addClass('selected')
}
)
})
pageEnd.innerHTML += test
//pageEnd.innerHTML += $(parent.cells[3]).text()
insertRow()
}
// insertRow assumes that the correct row in the table has the "selected" class added to it
function insertRow()
{
var Row = $('<tr>').append(
$('<td>').append('<input id="input1">'),
$('<td>').append('<select id="input2"><option value=""></option><option value="Yes">Yes</option><option value="No">No</option></select>'),
$('<td>').append('<select id="input3"><option value=""></option><option value="Natural">Natural</option><option value="1 Blank Used">1 Blank Used</option><option value="2 Blanks Used">2 Blanks Used</option></select>'),
$('<td>').append('<select id="input4"><option value=""></option><option value="vs Computer">vs Computer</option><option value="Online Game">Online Game</option><option value="Friendly Game">Friendly Game</option><option value="Club Game">Club Game</option><option value="Tournament Game">Tournament Game</option></select>'),
$('<td>').append('<input id="input5">')
)
$("#myTable tr.selected").after(Row)
}
Right now I'm just trying to get my code to insert a row into the table. I am trying to do this by using the code $(this).addClass('selected') to tag the row the user selected and then use it in my insert function to insert a row. However, nothing seems to happen. I am using pageEnd.innerHTML += "success" as a debugging tool to see if it is even getting there. Unexpectedly, it prints success twice when it should only print once, as in the test I ran every word was unique.
In any case I can't figure out why it's not working. Any help is appreciated. Thanks, ~Adam
You have two options to achieve this:
The first one as the others are suggesting i.e. by keeping a variable of outer this and then using this:
$('tr').each(function() {
var outerThis = this;
// inside another loop (not sure about children method, just an example)
$(outerThis).children("td:contains(test)").each(function() {
// do something with outerThis to operate on further
});
});
Another option to use Javascript's bind() method:
$('tr').each(function(i, trElement) {
// this == trElement
// inside another loop
$(outerThis).children("td:contains(test)").each(function(index, tdElement) {
$(this) // will be now tr element
$(tdElement) // will be td element
}.bind(this));
});
Try this:
function editRow(e) {
var eventEl = e.srcElement || e.target,
parent = eventEl.parentNode
parent = parent.parentNode
var test = $(parent.cells[0]).text()
$('tr').each(function(){
var outerThis = this;
outerThis.children("td:contains(test)").each(
function()
{
pageEnd.innerHTML += "success";
$(this).children().css('text-align', 'center');
}
)
})
pageEnd.innerHTML += test
//pageEnd.innerHTML += $(parent.cells[3]).text()
insertRow()
}
I set the outer this to a variable which you can use. Also textAlign is not a jQuery function. You need to use .css() and then specify text-align in that.
I have a dropdown that I want to be cloned and have a unique id. I managed to do it and it works on my website.
I am trying to make a "x" button to removed added clones and I can't get it to work.
The javascript:
var counter = 1;
function addInput(divName, template){
if (counter == 5) {
document.getElementById("add_more_text").remove();
} else {
var newdiv = document.createElement('div');
newdiv.innerHTML = document.getElementById(divName).innerHTML;
document.getElementById(template).appendChild(newdiv);
counter++;
}
var selectElements = document.querySelectorAll('select');
for (var i = 0; i < selectElements.length; i++){
selectElements[i].id = 'id-' + i;
selectElements[i].name = 'category' + i;
}
}
function removeInput(divName, template){
document.getElementById(template).removeChild(divName);
counter--;
}
The html:
<div id="template">
<select name="category0"><option>hi</option></select>
x
</div>
<div id="add_more"></div>
+ Add more
DEMO
Any help is much appreciated!
Simpler to modify remove function as follows:
function removeInput(obj) {
if (obj.parentNode.className == 'added') {
obj.parentNode.parentNode.removeChild(obj.parentNode);
counter--;
}
}
And have a link in template like this:
x
Class added is to distinguish new clones that can be removed:
newdiv.className = 'added';
Demo: http://jsfiddle.net/rjXXa/2/
in your onClick property
x
you are passing template and add_more
And in the handler function
function removeInput(divName, template){
the parameters are in a different order, so divName will contain 'template' and template will contain 'add_more'. Even if you fix this,
document.getElementById(template).removeChild(divName); // will throw error
because the div#add_more is not a child of div#template.
For fixing this, you need to pass a reference to the clicked element, like the following
x
and in your function
function removeInput(anchor){
var clone = anchor.parentNode; // div containing the anchor
if(clone.id!='template'){ // make sure we're not removing the original template
clone.parentNode.removeChild(clone);
counter--;
}
}
as in this Fiddle
Update
It's better to remove the add more option from display using css and make it visible later than removing/appending it in DOM, as follows
change the following in addInput() function
if (counter > 4) {
document.getElementById("add_more_text").style.display='none';
}
and in removeInput() function add
if (counter < 5) {
document.getElementById("add_more_text").style.display='block';
}
as in this Fiddle
Someone please help me how to add new function to remove the field, i have js script function that add new field as follows
<script language="javascript">
fields = 0;
function addInput() {
if (fields != 10) {
var htmlText = " <input type='text' name='friends[]' value='' size='auto' maxlength='45' /><br />";
var newElement = document.createElement('div');
newElement.id = 'new_field';
newElement.innerHTML = htmlText;
var fieldsArea = document.getElementById('new_field');
fieldsArea.appendChild(newElement);
fields += 1;
} else {
alert("Only 10 fields allowed.");
document.form.add.disabled=true;
}
}
</script>
but i need some helps to add new functions for removing field, For any suggestion and pointer I Would be appreciate.
Read here about removeChild() function removeChild() - mozilla developer
Edit Or here: removeChild() w3schools
First of all, there's already one problem I see with your code. You are setting each new field's ID to the same value, which is invalid HTML and asking for trouble. Be sure to fix that.
The .removeChild method of DOM elements is what you want. .removeChild will remove a node (element or text) from the DOM tree (the set of elements actually contained within the document) only if the node passed in is actually a child of that element, otherwise an error occurs.
You can easily remove the last field by finding the last child of its container:
function removeLastField() {
var fieldsArea = document.getElementById('new_field'),
lastChild = fieldsArea.lastChild;
if(lastChild) {
fieldsArea.removeChild(lastChild);
fields -= 1;
}
}