I am attempting to remove an entire element and recreate it on an event:
I cannot seem to get this right despite several variations of the same code:
For example on event, I need to remove the element and then recreate the same element. I do not want to remove the text:
This is what I have tried (experimental): The result is inconsistent and the code is repetitive.
function removeCreate(){
var input = document.getElementById('display');
var body = document.getElementsByTagName('body')[0];
if(!!input){
input.parentNode.removeChild(input);
input = document.createElement('input');
input.id = 'display';
input.setAttribute('type',"text");
body.appendChild(input);
} else {
input.parentNode.removeChild(input);
input = document.createElement('input');
input.id = 'display';
input.setAttribute('type',"text");
body.appendChild(input);
}
}
Your reason for removing your input element and re-creating it is quite unclear, but let's say it gets modified somehow and you want to "reset" its state.
When you say "I do not want to remove the text", the most probable thing I understand is that you want to keep the current value that the user has typed into your input.
If this fits your situation, then you could simply hold a "template" of your input element in memory, so that you can clone it when needed and use the clone to replace the one in DOM. When doing so, retrieve first the current input value, and inject it back into the cloned input.
Result:
var inputTemplate = document.createElement('input');
inputTemplate.setAttribute('type', 'text');
function cloneInput() {
var newInput = inputTemplate.cloneNode(true);
newInput.id = 'display';
return newInput;
}
var input = document.getElementById('display');
var body = document.getElementsByTagName('body')[0];
if(!!input){
// First retrieve the current value (what the user has typed / default value)
var value = input.value;
input.parentNode.removeChild(input);
input = cloneInput();
input.value = value; // Re-inject the value.
body.appendChild(input); // Note that this would put your input at the bottom of the page.
} else {
//input.parentNode.removeChild(input); // useless?
input = cloneInput();
body.appendChild(input);
}
Related
I'm currently learning JavaScript and I'm working on a mock pet adoption site. Super simple layout and functionality except for one issue. I have an error message that comes up when the 'submit' button is pressed and the user tries to submit a pet for adoption without clicking the 'terms and conditions' box. The error comes up, but if I click the button again (without checking the terms and conditions check box), it's like the error just appends another error message.
I am trying to get it where it won't create another error message. I have tried setting the alertMessage variable to an empty string at the end of the function in hopes of it resetting itself, but this does not work.
Thank you in advance for all of your help.
$('#add-pet').on('click', function() {
if (termsBox.checked) {
// Grab info from the form
let $name = $('#pet-name');
let $species = $('#pet-species');
let $notes = $('#pet-notes');
// Assemble the HTML of our new element with the above variables
let $newPet = $(
'<section class="six columns"><div class="card"><p><strong>Name:</strong> ' + $name.val() +
'</p><p><strong>Species:</strong> ' + $species.val() +
'</p><p><strong>Notes:</strong> ' + $notes.val() +
'</p><span class="close">×</span></div></section>'
);
// Attach the element to the page
$('#posted-pets').append($newPet);
// Make the 'x' in the corner remove the section it's contained within
$('.close').on('click', function() {
$(this).parents('section').remove();
});
// Reset form fields
$name.val('');
$species.val('Dog');
$notes.val('');
} else {
let br = document.createElement('BR');
let alertMessage = document.createTextNode('Please read the terms and conditions.');
let span = document.createElement('SPAN');
span.style.color = '#FF0000';
span.appendChild(alertMessage);
let termsLabel = document.getElementById('termsLabel');
termsLabel.appendChild(br);
termsLabel.appendChild(span);
alertMessage = '';
}
});
The easiest way is to use innerHTML DOM element property to clean up node's content:
else {
let br = document.createElement('BR');
let alertMessage = document.createTextNode('Please read the terms and conditions.');
let span = document.createElement('SPAN');
span.style.color = '#FF0000';
span.appendChild(alertMessage);
let termsLabel = document.getElementById('termsLabel');
termsLabel.innerHTML = ''; // this removes previous content of the node including all it's children
termsLabel.appendChild(br);
termsLabel.appendChild(span);
}
But I would use just:
else {
let termsLabel = document.getElementById('termsLabel');
termsLabel.innerHTML = 'Please read the terms and conditions.';
}
And all styles for termsLabel element should be declared via CSS in a way like
#termsLabel {
margin-top: 15px;
color: red;
}
UPD Here's the fiddler satisfying new requirements: https://jsfiddle.net/yy1z75e7/2/
Clear the element before appending the alert messages
termsLabel.innerHTML = '';
termsLabel.appendChild(br);
termsLabel.appendChild(span);
Or when creating the span give it a class or id, and then check termsLabel to see if it already has the span. If it doesn't then create it, otherwise don't do anything.
//cache this so you don't keep needing to call it over and over
let termsLabel = document.getElementById('termsLabel');
//querySelector() will return null if the span isn't in termsLabel
if(!termsLabel.querySelector('.errorMessage')){
let br = document.createElement('BR');
let alertMessage = document.createTextNode('Please read the terms and conditions.');
let span = document.createElement('SPAN');
span.style.color = '#FF0000';
span.classList.add("errorMessage");
span.appendChild(alertMessage);
termsLabel.appendChild(br);
termsLabel.appendChild(span);
}
This also gives you the ability to remove the message as well
document.querySelector('.errorMessage').remove()
Every time you click the button, and the code in the else clause executes, you are creating new elements. What you want to do instead is to check if the element, termsLabel lets say, is created first, and if it is then change its innerHtml or text values, and if it isn't then create the element instead.
The output of code below produces a line of text and then a button below the text.
How can I place the button beside the text?
var count = document.createTextNode('My text: ');
document.getElementById('container').appendChild(count);
var f = document.createElement('form');
f.setAttribute('method','POST');
f.setAttribute('action','test');
var text = document.createElement('input');
text.setAttribute('type','hidden');
text.setAttribute('name','text');
text.value = 'Hey! - hidden value';
var s = document.createElement('input'); //input element, Submit button
s.setAttribute('type','submit');
s.setAttribute('value','Hey!');
f.appendChild(text);
f.appendChild(s);
document.getElementById('container').appendChild(f);
s.onclick=function(){
f.submit();
};
jsFiddle: http://jsfiddle.net/bobbyrne01/hk0annoq/
The display attribute of form elements is set to block by default, which means that when they're created they'll skip one line within a paragraph. To solve this, one approach would be to make the form's display atrribute to inline or inline-block:
f.style.display = 'inline';
Here:
var f = document.createElement('form');
f.setAttribute('method','POST');
f.setAttribute('action','test');
f.style.display = 'inline';
Your updated fiddle here.
Update:
Expanding epascarello's answer, a more correct approach would be:
var f = document.createElement('form');
f.setAttribute('method','POST');
f.setAttribute('action','test');
// Create your label
var label = document.createElement('label');
// Set its text
var count = document.createTextNode('My Text: ');
var text = document.createElement('input');
text.setAttribute('type','hidden');
text.setAttribute('name','text');
text.value = 'Hey! - hidden value';
var s = document.createElement('input'); //input element, Submit button
s.setAttribute('type','submit');
s.setAttribute('value','Hey!');
// Append your text, hidden input and submit button to the label
label.appendChild(count);
label.appendChild(text);
label.appendChild(s);
// Append the label to the form
f.appendChild(label);
// Append the form to the container
document.getElementById('container').appendChild(f);
Because it gives the document better semantics.
What you have
<text node - inline>
<form - block - causes new line>
You would need to append it inside the form, not the container.
f.appendChild(count);
f.appendChild(text);
f.appendChild(s);
document.getElementById('container').appendChild(f);
You should also look at using a label element since that is how you are treating that text.
It's easier than what they say and no CSS needed, look at HERE
You just had to put 'count' inside the form rather than the container
f.appendChild(count);
instead of
document.getElementById('container').appendChild(count);
I have the following js code:
function createConBox() {
var charDiv = document.getElementById("characterList"); // reference to "characterList" div
header = document.createElement("p"); // creates the <p> tag
charDiv.appendChild(header); // adds the <p> tag to the parent node
title = document.createTextNode("Show Only Lines By:"); // creates the text string
header.appendChild(title); // adds the text string to the parent node
// create select box and add elements
selectBox = document.createElement("select");
selectBox.setAttribute("id", "cList");
charDiv.appendChild(selectBox);
charNames = uniqueElemText("h3"); // array of character names
newOption = document.createElement("option");
selectBox.appendChild(newOption);
newOptionTitle = document.createTextNode("Show All Lines");
newOption.appendChild(newOptionTitle);
for (i = 0; i < charNames.length; i++) {
newOption = document.createElement("option");
selectBox.appendChild(newOption);
newOptionTitle = document.createTextNode(charNames[i]);
newOption.appendChild(newOptionTitle);
}
}
function showLines() {
alert("The Box has been changed");
}
Every time the option in the box is changed, I want it to call 'showLines()'. However, every time I try to implement an event, I can only get it to trigger when the page loads, and never again thereafter.
selectBox.onchange = showLines; should solve your problem.
in some browsers onchange get fired only after blurring select box. to over come this you can use onclick instead of onchange
My guess is that you're doing this:
selectBox.onchange = showLines();
If that's the case, just remove the ():
selectBox.onchange = showLines;
When I pass dynamically id in case then what I do:
var selectcell = tablerow.insertCell(1);
var selectelmt = document.createElement('select');
selectelmt.name = 'Select';
selectelmt.value = 'select';
selectelmt.classList = 'form-control input-sm cobclass';
selectelmt.onchange= onselectchange(i);
selectelmt.id = 'cobselect' + i;
selectelmt.options[0] = new Option('select');
selectcell.appendChild(selectelmt);
// ddrbind(i);
show();
i++;`
I'm writing a simple to-do list. that a user input a text and the it's added as a checkbox. But i'm getting this error i have no idea what's it about
INVALID_CHARACTER_ERR: DOM Exception 5
window.onload = function(){
var textBox = document.getElementById("taskInput"),
submitBtn = document.getElementById("submit"),
taskPool = document.getElementById("todoTask");
submitBtn.addEventListener("click", function(){
var task = document.createElement("<input type=\"checkbox\">" + textBox.value + "</input>");
taskPool.appendChild(task);
});
}
document.createElement takes the tag name only as its parameter, you'll have to set the type and value after
var task = document.createElement("input")
task.type = "checkbox";
task.value = textBox.value;
Also input tags are empty, there are no closing tag or inner html, the value is set as an attribute in markup.
I have got this working with the start point as a span, but I want to have the form still function if javascript is disabled in the browser this is how I had it working originally. I'm still very new to javascript, can someone lend a hand please.
window.onload = function() {
document.getElementById('container').onclick = function(event) {
var span, input, text;
// Get the event (handle MS difference)
event = event || window.event;
// Get the root element of the event (handle MS difference)
span = event.target || event.srcElement;
// If it's a span...
if (span && span.tagName.toUpperCase() === "SPAN") {
// Hide it
span.style.display = "none";
// Get its text
text = span.innerHTML;
// Create an input
input = document.createElement("input");
input.type = "text";
input.size = Math.max(text.length / 4 * 3, 4);
span.parentNode.insertBefore(input, span);
// Focus it, hook blur to undo
input.focus();
input.onblur = function() {
// Remove the input
span.parentNode.removeChild(input);
// Update the span
span.innerHTML = input.value;
// Show the span again
span.style.display = "";
};
}
};
};
Best way to do this would be to show the input first, then quickly swap it out when the page loads, then swap it back when the user clicks.
You might also consider using the form element the whole time, but just changing CSS classes on it to make it look like normal text. This would make your UI cleaner and easier to maintain in the future.
Then just put the input fields there from the start, and hide them with a script that runs when the form has loaded. That way all the fields will be visible if Javascript is not supported.
I think your best option would be to wrap a form with noscript tags which will fire when Javascript is disabled in a browser. If they display even while in the noscript tags then just set them as not visible with Javascript.
if you have jQuery, something like this should work.
function makeElementIntoClickableText(elm){
$(elm).parent().append("<div onClick='switchToInput(this);'>"+ elm.value +"</div>");
$(elm).hide();
}
function switchToInput(elm){
$(elm).prev().prev().show();
$(elm).hide();
}
makeElementIntoClickableText($("input")[0]);
use the readonly attribute in the input elements:
<input type="text" readonly />
And then remove that attribute with JavaScript in the onclick event handler, reassigning it on blur:
var inputs = document.getElementsByTagName('input');
for (i=0; i < inputs.length; i++) {
inputs[i].setAttribute('readonly',true);
inputs[i].onclick = function(){
this.removeAttribute('readonly');
};
inputs[i].onblur = function(){
this.setAttribute('readonly',true);
};
}
JS Fiddle demo.