JS : innerHTML does not update - javascript

I have a simple function to change the innerHTML of a span element.
here is the code :
function changeElementAnswered() {
var dataq = this.getAttribute('data-num');
var ele = document.getElementById('qp-' + dataq);
if(ele){
if(this.value != ""){
ele.className = 'qp-item qp-item-answered';
} else {
ele.className = 'qp-item qp-item-unanswered';
}
var cele = document.getElementById('revq-' + dataq);
if(cele) {
cele.innerHTML = this.value.toString();
alert(cele.innerHTML);
}
}
}
and this is the HTML code :
<span class="test-answer-rev" data-num="1" id="revq-1"></span>
I successfully update the inner html of the span class. the alert function shows the correct answer but the problem is that the HTML code (of the current instance) does not get updated (can't see changes in Developer mode). What am i missing here ?
-- Already tried .textContent is doesn't work
Update 1 : I use the span in a popup which means the parent div is hidden (display:none;)

innerHTML will make changes for the current instance of the web page only. It wont change the original HTML code in your file. If you go to developer tools and look at the HTML it will be changed, but you cannot manipulate the source file using innerHTML.
function changeElementAnswered(e) {
var dataq = e.getAttribute('data-num');
var ele = document.getElementById('qp-' + dataq);
if(ele){
if(ele.value != ""){
ele.className = 'qp-item qp-item-answered';
} else {
ele.className = 'qp-item qp-item-unanswered';
}
var cele = document.getElementById('revq-' + dataq);
if(cele) {
cele.innerHTML = ele.value.toString();
alert(cele.innerHTML);
}
}
}
<span class="test-answer-rev" onclick="changeElementAnswered(this)" data-num="1" id="revq-1">gg</span>
<input value="a" id="qp-1">

Related

How to create a toggle button that dynamically changes HTML content?

I have been working on this question for several days, and have researched it on SO as well as the web at large and was unable to find material that helped me solve it.
I am trying to create a weather app that can toggle the weather units displayed between Fahrenheit and Celsius. I start by appending the weather in Fahrenheit, and then I have created an event handler that conditionally changes the inner content of the associated element based on whether that element is currently displaying "F" or "C".
As it is, my app successfully loads with the Fahrenheit temperature, and toggles to Celsius on click, but it will not toggle back to Fahrenheit. I assume there is some issue with how the events are registered, but for the life of me I cannot figure it out.
Here is my code:
var fahr = document.createElement("a");
fahr.attr = ("href", "#");
fahr.className = "tempUnit";
fahr.innerHTML = tempf + "°F" + "<br/>";
$("#currentWeather").append(fahr);
var cels = document.createElement("a");
cels.attr = ("href", "#");
cels.className = "tempUnit";
cels.innerHTML = tempc + "°C" + "<br/>";
var units = document.getElementsByClassName("tempUnit");
$(".tempUnit").click(function() {
if (units[0].innerHTML.indexOf("F") != -1) {
$(".tempUnit").replaceWith(cels);
} else {
$(".tempUnit").replaceWith(fahr);
}
})
Thank you so much in advance! Happy to provide additional information if necessary.
Currently what you are using is called a direct binding which will only attach to element that exist on the page at the time your code makes the event binding call.
As you using replaceWith(), existing element is replaced with new element and event handlers are not attached with them.
You need to use Event Delegation using .on() delegated-events approach.
General Syntax
$(parentStaticContainer).on('event','selector',callback_function)
Example, Also use this i.e. current element context and use setAttribute() to update href element
$("#currentWeather").on("click", ".tempUnit", function() {
if (this.innerHTML.indexOf("F") != -1) {
$(this).replaceWith(cels);
}
else {
$(this).replaceWith(fahr);
}
})
var tempf = 212;
var tempc = 100;
var fahr = document.createElement("a");
fahr.setAttribute("href", "#");
fahr.className = "tempUnit";
fahr.innerHTML = tempf + "°F" + "<br/>";
$("#currentWeather").append(fahr);
var cels = document.createElement("a");
cels.setAttribute("href", "#");
cels.className = "tempUnit";
cels.innerHTML = tempc + "°C" + "<br/>";
$("#currentWeather").on("click", ".tempUnit", function() {
if (this.innerHTML.indexOf("F") != -1) {
$(this).replaceWith(cels);
} else {
$(this).replaceWith(fahr);
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="currentWeather"></div>

Cannot retrieve the HTML Dom object

I am using IE11 for this since that is my companys standard browser.
I am working on a solution to catch the paste event when pasting a screen dump into the web application. So far so good but after I have pasted the image I would like to change the size. Preferable before actually so I don't get a jumping application.
I have create a jsfiddle where you can see the entire test application: http://jsfiddle.net/e5f5gLan/3/
Do like this when running the jsfiddle:
Make a screen shot
Put the marker in the red square
Press Ctrl + v
Now the intention is that the pasted image should become 100px x 100px in size. It doesn't.
The problem is that I am not getting hold of the DOM object so I can set the style/size of the image.
The significant part is at the end of the javascript (I guess...):
var image_container = document.getElementById('pastearea');
var image = image_container.getElementsByTagName("img");
image[0].setAttribute("style", "width: 100px; height: 100px");
First of all, I imagined that the img element would become part of an array and that I should access the only img-element using image[0]. But then I get the error "Not possible to get setAttribute for a reference that is undefined or null. " (freely translated from Swedish...)
Ok, perhaps it understands it is only one element and just returns an object that isn't an array. So I changed the last row above to:
image.setAttribute("style", "width: 100px; height: 100px");
Then I get that setAttribute is not supported by the object.
If I create an HTML page with similar structure (img inside div) and just tries to change the size, then it works. Check out this one (click the button to shrink the image): http://jsfiddle.net/m4kzd7jp/3/
How can I change change the size of the image before or after I have pasted it?
Yeah I added the style and it worked to keep it 100px height/width.
#pastearea img { width: 100px; height: 100px; }
I tested your code and the filelist was always 0. If you want to handle this through code, here's what I was using in our project. basically you should be looping items not files and checking if it is a file.
function (e) {
var clip = e.clipboardData || window.clipboardData;
if (clip) {
var preInsert = getData(); // this pulled the input box text or div html
for (var i = 0; i < clip.items.length; i++) {
var item = clip.items[i];
if (item.kind == "file" &&
item.type.indexOf('image/') !== -1) {
var fr = new FileReader();
fr.onloadend = function () {
if (preInsert == getData()) // if nothing changed, we'll handle it otherwise it was already handled
setData(fr.result);
};
var data = item.getAsFile();
fr.readAsDataURL(data);
}
}
}
}
This area shows what I was doing in angular to get/set
var getSelection = function() {
if (window.getSelection && window.getSelection().rangeCount > 0) //FF,Chrome,Opera,Safari,IE9+
{
return window.getSelection().getRangeAt(0).cloneRange();
}
else if (document.selection)//IE 8 and lower
{
return document.selection.createRange();
}
return null;
}
var isInputTextarea = false; // I was being more generic in my angular directive
var getData = function () {
if (isInputTextarea)
return $element.val();
return $element.html();
};
var setData = function (src) {
if (isInputTextarea) {
$element.val(function (index, value) {
return value + " " + "<img src='" + src + "'>";
});
}
else {
var selection = getSelection(); // I presume we have focus at this point, since it is a paste event
if (selection) {
var img = document.createElement("img");
img.src = src;
selection.insertNode(img);
}
}
};

Input box value vanishes when adding a new one

I'm working on a web app where I need to add a number of input boxes one after the other in order to get commands from the user. I add them using JavaScript to a div with a unique ID to each. The problem I have is once I press enter and the JavaScript function is called to add the next one, the previous input box empties out, and I don't know why.
Here is sample code:
var i = 0;
add_input();
function add_input() {
i++;
document.getElementById('main').innerHTML += "<p>> <input type='text' style='width:90%' id='input" + i + "' onkeypress='press_key(event, this)'></p>";
document.getElementById('input' + i).focus();
}
function press_key(e, t) {
if (e.keyCode == 13) {
add_input();
}
}
<div id='main'></div>
innerHTML will override all existing content and replace them with new ones. You should create a new input element and use insertNode instead.
The addition assignment operator will add the right hand value to the left hand value and then assign the resultant value to the left hand side.
For a quick example:
x += y;
// is equivalent to
x = x + y;
In your code you are basically taking the existing HTML, adding a new chunk of HTML and then assigning that new HTML to the original element replacing the existing HTML. Since the value is not set in the HTML but stored in the DOM it is lost as soon as you assign new HTML to the element (which is when the browser renders it to the DOM replacing the previous DOM).
You could use insertNode as mentioned above or set the HTML attribute to store the value first as the below example shows. However note that this solution is purely to show why the values are disappearing. Doing it this way has an issue that if any of the previous input values are changed only the original value for those inputs would be preserved.
var i = 0;
add_input();
function add_input() {
var curInput = document.getElementById('input' + i);
if (curInput) {
curInput.setAttribute('value', curInput.value);
}
++i;
document.getElementById('main').innerHTML += "<p>> <input type='text' style='width:90%' id='input" + i + "' onkeypress='press_key(event, this)'></p>";
document.getElementById('input' + i).focus();
}
function press_key(e, t) {
if (e.keyCode == 13) {
add_input();
}
}
<div id='main'></div>
innerHTML overwrites all html from the selected element including any user/javascript actions performed on the given html. Thus your input values will be erased with the new html. You are going to want to create an element and then use appendChild. This will maintain the state of your current html elements.
var i = 0;
function add_input()
{
i++;
var input = document.createElement('input');
input.onkeypress=press_key;
input.id = 'input' + i;
document.body.appendChild(input);
input.focus();
}
function press_key(e)
{
//`t` argument is no longer used. Use `this` instead.
if (e.keyCode == 13)
{
add_input();
}
}
<html>
<head>
<script>
</script>
</head>
<body onload='add_input()'>
<div id='main'>
</div>
</body>
</html>
As stated above, your other values disappear due to the inner workings of "innerHTML". In fact, when you do string.innerHTML += string it will replace the HTML for it (meaning what was there before is totally gone and is de-facto replaced with fresh new HTML).
What you want to use is probably appendChild().
With little rewriting I have managed to make your code work:
http://jsfiddle.net/gs1s0fsx/
var i = 0;
function add_input() {
i++;
var main = document.getElementById('main'),
p = document.createElement("p"),
arrow = document.createTextNode('>'),
el = document.createElement('input');
el.type = "text";
el.style = "width:90%";
el.id = "input" + i;
el.addEventListener("keypress", press_key);
main.appendChild(p);
main.appendChild(arrow);
main.appendChild(el);
el.focus();
}
function press_key(e, t) {
if (e.keyCode == 13) {
add_input();
}
}
add
<div id='main'></div>
Hope this helps.

javascript not changing the text color

I have a function that I want to change the font color of the user entered string if it is equal to a certain word located in an array.. So far when I step through it it says that it changes the font color but it actually never updates it to the screen and I don't know why. Here is what I have so far
function getLastWord() {
var input = document.getElementById("my_text");
//var input = document.getElementById(textArea.value);
//var lineIn = document.getElementById(my_text).innerHTML;
var inputValue = input.value;
var lastWordTyped
var changeColorOfWord;
if (input == null) {
input == " ";
}
//lastWordTyped = input.substr(input.trim().lastIndexOf(" ") + 1);
lastWordTyped = inputValue.substr(inputValue.trim().lastIndexOf(" ") + 1);
if (input != null) {
for (var i = 0; i < reservedKeyWords.length; i++) {
if (reservedKeyWords[i] === lastWordTyped) {
lastWordTyped = lastWordTyped.fontcolor("blue");
my_text.replace(inputValue, lastWordTyped);
} else {
}
}
}
}
I see two issues with the code thus far.
You are using 'fontcolor("blue")' parameter on the lastWordTyped. The proper syntax to change color is element.style.color="#CCC".
You will need to wrap the last typed word in a span so you can target it and apply the color to just that word.
string.fontcolor is legacy, and should not be used even though I could see it as a viable option in this case
Essentially, what you are doing is adding font tags around the word:
var txt = 'hello world';
txt = txt.fontcolor('blue');
//txt = '<font color="blue">hello world</font>';
You do not show what you do with the result, but if you actually put it in an HTML element it should work, even though instead of using fontcolor, I'd rather use element.style.color. This would require slightly more work though:
var ele = document.querySelector('#my_text');
ele.style.color = 'blue';
ele.innerHTML = lastWordTyped;
If you still want to go with the .fontcolor method, you could just keep what you have in the question and add
input.innerHTML = my_text;

Accessing HTML Elements that have been created by setting innerHTML

I have a Function which makes an ajax call and then return a piece of html that is inserted into a table's td element. using element.innerHTML=ajaxResult; Now I want to access the elements in the ajaxResult that have the name attribute as special. So I do a document.getElementsByName('special') and expect to get 4-5 elements. But I actually get none.
This makes it impossible for me to access those elements and I am stuck. Please help me resolve this. Thanks in Advance!
I think this is related to the dom not reloading after I set innerHTML. But not sure how to reload it.
I am using IE8 in IE8 compatibility view and IE7 standards :(
EDIT
This is my function
function handleStateChange()
{
if(ajaxRequest.readyState==4 && ajaxRequest.status==200) {
var responseStr = ajaxRequest.responseText;
var splitResult = responseStr.split("$$$$$$$$$$$$$$$$$$$$");
var leftHtml= splitResult [0];
var rightHtml= splitResult [1];
document.getElementById("div1").innerHTML=leftHtml;
if(rightHtml !="") {
document.getElementById("div2").innerHTML=rightHtml;
}
if(splitResult.length >=3 ){
var appActionflag = splitResult [2];
document.getElementById("userAction").innerHTML=appActionflag;
}
if(splitResult.length >= 4 ){
var userId = splitResult [3];
document.getElementById("userId").innerHTML=userId;
}
reverseDNASwitch();
var grpList = document.getElementsByName('parmGrpId');
alert('javascript is working! Found:'+grpList.length);
for(var i=0;i<grpList.length;i++){
alert('Got GroupId: '+ (i));
var grpTd = grpList[i];
grpTd.innnerHTML='Hi';
}
}
}
If the table cell you're adding to is, itself, in the DOM, that should work. (And so I may have to delete this answer; originally I thought document.getElementsByName had been deprecated, but I was mistaken). Here's an example using getElementsByName:
Live Copy | Live Source
(function() {
// Get the target
var target = document.getElementById("target");
// Dynamically add content
target.innerHTML =
'<div name="special">special 1</div>' +
'<div name="special">special 2</div>' +
'<div name="special">special 3</div>';
// Get those elements
var list = document.getElementsByName("special");
// Prove we got them
var p = document.createElement('p');
p.innerHTML = "Found " + list.length + " 'special' elements";
document.body.appendChild(p);
})();
Of course, because it's a function of document, that will find all of the elements with name="special", not just the ones you added to the table cell.
The above does not work on IE if the elements aren't allowed to have the name attribute. So for instance, if you look for getElementsByName("special"). it will ignore <div name="special"> but find <input name="special">, because name is not a valid attribute for div elements. Details in this MSDN article. Worse, IE will include elements whose id matches, even though of course that has nothing to do with name. sigh
Unless you need to support IE7 and earlier (e.g., unless you're developing for China), you can use Element#querySelectorAll with the selector '[name="special"]'. That will look only within the element for elements that use that name attribute.
Example: Live Copy | Live Source
(function() {
// Get the target
var target = document.getElementById("target");
// Dynamically add content
target.innerHTML =
'<div name="special">special 1</div>' +
'<div name="special">special 2</div>' +
'<div name="special">special 3</div>';
// Get those elements
var list = target.querySelectorAll('[name="special"]');
// Prove we got them
var p = document.createElement('p');
p.innerHTML = "Found " + list.length + " 'special' elements";
document.body.appendChild(p);
})();
If you need to support IE7 or earlier, you might look at this other Stack Overflow question and my answer to it. The question points to this article about adding querySelectorAll to document, and my answer to the question talks about how to emulate that at an element-specific level.
So combining the code from that article with my answer to the other question and the examples above, we get:
Live Copy | Live Source
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
<div id="target"></div>
<script>
(function() {
// IE7 support for querySelectorAll. Supports multiple / grouped selectors and the attribute selector with a "for" attribute. http://www.codecouch.com/
if (!document.querySelectorAll) {
(function(d, s) {
d=document, s=d.createStyleSheet();
d.querySelectorAll = function(r, c, i, j, a) {
a=d.all, c=[], r = r.replace(/\[for\b/gi, '[htmlFor').split(',');
for (i=r.length; i--;) {
s.addRule(r[i], 'k:v');
for (j=a.length; j--;) a[j].currentStyle.k && c.push(a[j]);
s.removeRule(0);
}
return c;
}
})();
}
var qsaWorker = (function() {
var idAllocator = 10000;
function qsaWorkerShim(element, selector) {
var needsID = element.id === "";
if (needsID) {
++idAllocator;
element.id = "__qsa" + idAllocator;
}
try {
return document.querySelectorAll("#" + element.id + " " + selector);
}
finally {
if (needsID) {
element.id = "";
}
}
}
function qsaWorkerWrap(element, selector) {
return element.querySelectorAll(selector);
}
// Return the one this browser wants to use
return document.createElement('div').querySelectorAll ? qsaWorkerWrap : qsaWorkerShim;
})();
// Get the target
var target = document.getElementById("target");
// Dynamically add content
target.innerHTML =
'<div name="special">special 1</div>' +
'<div name="special">special 2</div>' +
'<div name="special">special 3</div>';
// Get those elements
var list = qsaWorker(target, '[name="special"]');
// Prove we got them
var p = document.createElement('p');
p.innerHTML = "Found " + list.length + " 'special' elements";
document.body.appendChild(p);
})();
</script>
</body>
</html>
Which works in IE7.
As an option for your specific scenario, where you want to get elements with a specific attribute (and value), you can use a function like this:
function getElementsByAttribute(options) {
/*if (container.querySelectorAll) {
var selector = '';
if (options.tagFilter) {
selector += options.tagFilter;
}
selector += '[' + options.attr;
if (options.val) {
selector += '="' + options.val.replace(/"/g, '\\"') + '"';
}
selector += ']';
return Array.prototype.slice.call(options.container.querySelectorAll(selector));
}*/
var elements = options.container.getElementsByTagName(options.tagFilter || "*"),
ret = [],
i, cur,
matches = (function () {
if (options.val) {
return function (el) {
return el.getAttribute(options.attr) === options.val;
};
} else {
return function (el) {
return el.hasAttribute(options.attr);
};
}
})();
for (i = 0; i < elements.length; i++) {
cur = elements[i];
if (matches(cur)) {
ret.push(cur);
}
}
return ret;
}
And you call it like:
window.onload = function () {
var contain = document.getElementById("container"),
els = getElementsByAttribute({
container: contain,
attr: "name",
val: "special",
tagFilter: ""
});
console.log("els", els);
};
DEMO: http://jsfiddle.net/cxq6t/1/
(I kept in my original logic for supporting querySelectorAll, but proved not to work in old IE with invalid attributes, per the comments)
The object you pass to the function accepts:
container: containing element to look through
attr: the attribute to look for
val: optional value to match against
tagFilter: optional filter for the tagName of matched elements
I tested in IE7/8 to see if the <div name="special"> would match, and it does. As well as the other <input />s.
If you ever wanted to expand the selector to be more complicated things like what querySelectorAll supports, you could use a polyfill like T.J.Crowder's. But this seems to get the job done.

Categories