Appending HTML element with Javascript, element isn't seen? - javascript

I'm still new to javascript, so expect to see a lot of bad programming practices...
function addButton(name, state) {
numButtons += 1;
if (name === '') {
var i = 0;
while(buttonStates.hasOwnProperty("button" + i) === true) i++;
name = "button" + i;
}
document.getElementById("buttonTable").innerHTML +=
"<tr>\
<td>\
<p id=\"buttonName" + numButtons + "\" class=\"buttonName\">" + name + "</p>\
</td><td>\
<button id=\"" + name + "\" onclick=\"setButton(this, 'toggle')\" class=\"button\">OFF</button>\
</td>\
</tr>";
//===IMPORTANT AREA 1==========================================================//
//setTimeout(function(){setButton(document.getElementById(name), state)}, 0); //works
setButton(document.getElementById(name), state); //doesn't work, no change
//=============================================================================//
}
function setButton(elem, state) {
//this is where the button's colors are set to light colors
//notice how I am using elem.style.backgroundColor
if(String(state) === 'toggle') state = !buttonStates[elem.id];
if (String(state) === 'true') {
buttonStates[elem.id] = true;
elem.style.backgroundColor = "rgb(112,192,112)";
elem.textContent = 'ON';
} else {
buttonStates[elem.id] = false;
elem.style.backgroundColor = "rgb(255,128,128)";
elem.textContent = 'OFF';
}
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState === 4 && this.status === 200) {
document.getElementById("demo").innerHTML = this.responseText;
//===IMPORTANT AREA 2==========================================================//
if (buttonStates[elem.id] === true) {
elem.style.backgroundColor = 'green'; //doesn't work, no change. Notice how I am, again, using elem.style.backgroundColor
//document.getElementById(elem.id).style.backgroundColor = 'green'; //works
} else {
elem.style.backgroundColor = 'red';
}
//=============================================================================//
} else {
document.getElementById("demo").innerHTML = "readyState: " + this.readyState + "<br>status: " + this.status;
}
};
xhttp.open("POST", "/buttonToggle", true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send(elem.id + "=" + buttonStates[elem.id]);
}
So basically I add an HTML button in addButton(), which calls setButton() and passes the new element to that function. In setButton(), it first sets the element's color to light-green or light-red, indicating that the server has not yet updated the state of the button. This part works fine, the button's color DOES change. HOWEVER, in the callback function for the server request, the button refuses to change color in the exact same method as used before. I have found ways around it (either by using setTimeout() with a time of 0ms, or by using the passed element to again get the element from document), but I want to know WHY this happens. It seems to only be a problem in the callback function. I have verified that the callback function does execute and that the code for changing the color is executed.
As a side note, if I have multiple buttons, the last button works fine and all those before it do not work, their color is still light-green or light-red.
Notice buttons 0-5 are all a light color, yet button6 is solid, WHY?!?

Different elements on the HTML doc should have different unique ids. Your all buttons have the same id so only last one is working.
Make your ids unique by using 'button' + i like you are using name.

Okay, I don´t get the current error and why your code doesn´t work. Maybe we need to see the whole code?
But you are definitely searching for the keyword "event loop".
When your code works when you are running it in a timeout, your code needs to be running async.
See more details here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
If you post the whole code, I will take a look again, but maybe this already helps.
And if this are your first steps in programming, you are doing it great!

Related

AJAX based search returning page information

I found the source of the error but do not know how to fix it. I'm using codeigniter and I'm trying to make a textbox with search results showing under it to help the user find what they are looking for. Think similar to google's search. When I make the AJAX call, it's returning everything on the webpage as well as the search results.
Example of issue: https://gyazo.com/244ae8f3835233a2690512cebd65876d
That textbox within the div should not be there as well as the white space. Using inspect element I realized the white spaces are my links to my CSS and JS pages. Then there's the textbox which is from my view.
I believe the issue lies within my JS.
//Gets the browser specific XmlHttpRequest Object
function getXmlHttpRequestObject() {
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
} else if (window.ActiveXObject) {
return new ActiveXObject("Microsoft.XMLHTTP");
} else {
alert("Your Browser Sucks!\nIt's about time to upgrade don't you think?");
}
}
//Our XmlHttpRequest object to get the auto suggest
var searchReq = getXmlHttpRequestObject();
//Called from keyup on the search textbox.
//Starts the AJAX request.
function searchSuggest() {
if (searchReq.readyState == 4 || searchReq.readyState == 0) {
var str = encodeURI(document.getElementById('txtSearch').value);
searchReq.open("GET", '?search=' + str, true);
searchReq.onreadystatechange = handleSearchSuggest;
searchReq.send(null);
}
}
//Mouse over function
function suggestOver(div_value) {
div_value.className = 'suggest_link_over';
}
//Mouse out function
function suggestOut(div_value) {
div_value.className = 'suggest_link';
}
//Click function
function setSearch(value) {
document.getElementById('txtSearch').value = value;
document.getElementById('search_suggest').innerHTML = '';
}
//Called when the AJAX response is returned.
function handleSearchSuggest() {
if (searchReq.readyState == 4) {
var ss = document.getElementById('search_suggest');
ss.innerHTML = '';
var str = searchReq.responseText.split("\n");
for (i = 0; i < str.length - 1; i++) {
var suggest = '<div onmouseover="javascript:suggestOver(this);" ';
suggest += 'onmouseout="javascript:suggestOut(this);" ';
suggest += 'onclick="javascript:setSearch(this.innerHTML);" ';
suggest += 'class="suggest_link">' + str[i] + '</div>';
ss.innerHTML += suggest;
}
}
}
More specifically the getXmlHttpRequestObject function. it is returning the entire page including my header and footer. I don't believe any more info is needed but if anyone feels that way, I'll supply the view and controller.
https://gyazo.com/d0c43326191a4b09cc4b1d85d67a1bf6
This image shows the console and how the response and response text are the entire page instead of just the results.
Your call to the view method is loading the header view, the suggest view and the footer view while your suggest model is echoing the data that you're after.
You could just remove the line $this->view("suggest"); and your suggestions will be echoed.
This isn't great though. I would pass the titles back to the controller from the model then create a new controller method that outputs the data in a structured way (probably JSON).

Can't figure out why my JS doesn't work

I've been messing around with JavaScript samples and ever since I edited this one I can't figure out why it wont work. Everything looks fine to me, but here is the code (JSFiddle)
https://jsfiddle.net/en2a8c1v/1/
function click(e) {
document.body.style.backgroundColor='" + e.target.id + "';
}
document.addEventListener('DOMContentLoaded', function () {
var divs = document.querySelectorAll('div');
for (var i = 0; i < divs.length; i++) {
divs[i].addEventListener('click', click);
}
});
First, make sure that in the JS settings you have no-wrap enabled (I used no-wrap head) in the load type dropdown.
Next, you need to understand that when you call e.target.id, this is already a string variable. You are literally making the background color "e.target.id". That isn't a color.
Simply change document.body.style.backgroundColor='" + e.target.id + "';
to document.body.style.backgroundColor= e.target.id;
I'm not going to touch on the fact that this is a terrible way to go about this as I am assuming you are just playing with event handling.
Maybe someone will find this usefull. Use CSS attribute: background-color:rgb(x,y,z);
You can do it on simple way, for example:
document.getElementById("elementID").style.backgroundColor = 'rgb('+ this.red + ', ' + this.green + ', ' + this.blue + ')';
These r,g,b values can be, for example:
this.red = 0;
this.green = 255;
this.blue = 130;

setInterval function cannot use outer variable

Why is prevColor always undefined?
This code should log a new color (actualColor) and the previous color (prevColor). However I cannot save into prevColor from inside the setInterval function. Where is the bug? I don´t think it is a context problem. But I´m not sure. There´s no this inside...
Can you tell me how I can save the value of actualColor in prevColor from inside the setInterval function?
var actualColor;
var prevColor;
// do some user action and change actualColor
setInterval(function () {
// only log the color if it differs from prevColor
if (actualColor != prevColor) {
console.log("actualColor: " + actualColor + ", prevColor: " + prevColor);
}
prevColor = actualColor;
}, 100);
Console:
actualColor: acff06, prevColor: undefined
I think it must be your context -I made a simple webpage with all the bits you have above, and it works fine -even without setting initial values on the variables:
I placed your code in a script tag in the HEAD, and added
<input
type="text"
id="actualColor"
/>
<input
type="button"
onclick = "actualColor = document.getElementById('actualColor').value;"
value = "change colour" />
to provide a way of changing actualColor in the webpage (rather than using the console)
You need to initialize the value of the prevColor, otherwise first time it will be undefined
Just do
var actualColor;
var prevColor = "";
// do some user action and change actualColor
setInterval(function () {
// only log the color if it differs from prevColor
if (actualColor != prevColor) {
console.log("actualColor: " + actualColor + ", prevColor: " + prevColor);
}
prevColor = actualColor;
}, 100);

How can I change the colour of a button using JavaScript?

I want to change the coilor of a button on mouse click from white to red then from red back to white if click again. I tried like this:
<script language="JavaScript">
<!--
function changecolor(Id){
var series = "0";
var a = window.getComputedStyle(document.getElementById(Id)).backgroundColor;
var b = 2
if (a == "#FF4F4F") {
b = 1
}
if (b == 1) {
document.getElementById(Id).style.backgroundColor = "#FFFFFF";
}
if (b == 2) {
document.getElementById(Id).style.backgroundColor = "#FF4F4F";
}
}
//-->
</script>
It won't work. This will make the button go red in mozilla, chrome but it won't click back to white. IE says "error in page". The button HTML code is:
<input type = "button" Id = "01" value="01" onClick="changecolor('01')">
Something missing from my CSS styles. It looks like the first read (of the colour) is a null value but it does makes the button go red -in the two browsers- the way this function of mine is constructed. Then it looks like the if condition is not working properly, to see the red and make it white.
The computed style of a background colour is of the format rgb(###, ###, ###) (or variations thereof, such as different whitespace or rgba) Therefore comparing with #xxxxxx will not work.
Since you're assigning to style.backgroundColor, you can simply read back:
var elem = document.getElementById(Id);
if( elem.style.backgroundColor == "#FF4F4F") {
elem.style.backgroundColor = "#FFFFFF";
}
else {
elem.style.backgroundColor = "#FF4F4F";
}
Feel free to switch the cases around as needed (based on how it should change the first time), but this will work because the browser will keep whatever you assigned to it.
However, in general, you should have a more reliable toggle:
var elem = document.getElementById(Id);
if( elem._toggle) {
elem.style.backgroundColor = "#FFFFFF";
}
else {
elem.style.backgroundColor = "#FF4F4F";
}
elem._toggle = !elem._toggle;
This will toggle reliably.

Javascript loop to update image is returning broken image

I am new to javascript and am trying to create this loop to simulate some dice rolls. When I click roll none of the images are refreshed and it ends with the broken image shown. Can anyone see where my error is?
function roll(){
for(x=0;x<10;x++){
var die_num1 = Math.ceil(Math.random()*6);
for(y=0;y<20;y++){
var picturetype1 = Math.ceil(Math.random()*3);
if (picturetype1 == 1){prefix1 = "die-";}
if (picturetype1 == 2){prefix1 = "dicet-";}
if (picturetype1 == 3){prefix1 = "dices-";}
document.getElementById("dice").src='http://localhost/CodeIgniter_2.1.2/dice/' + prefix1 + die_num1 + '.gif';
}
}
}
body:
<input type ="button" value = "Roll" onclick="roll()" >
<img name="dice" id="dice" src="http://localhost/CodeIgniter_2.1.2/dice/die-1.gif" >
I used adocument.write to make sure that at least the final image existed in my folder and it does. I would expect to see the images cycling through as the loop progresses though. Again, I have no experience with javascript and have put this together based on how I thought it should look. Any help will be appreciated.enter code here
I wouldn't expect browser as an event-driven environment even to consider updating the screen before you return from you roll(). You need to get acquainted with setTimeout and handle it as a sequence of timer events.
Thanks for setting me in the right direction. I have reworked this to use setTimeout as Michael suggested and it is working great. Only needed 1/10 of a second per iteration, not much but made all the difference.
function roll2(){
var timer = setTimeout ("roll2();", 100);
i++;
if(i >= 15) clearTimeout(timer);
var die_num1 = Math.ceil(Math.random()*6);
var picturetype1 = Math.ceil(Math.random()*3);
if (picturetype1 == 1){prefix1 = "die-";}
if (picturetype1 == 2){prefix1 = "dicet-";}
if (picturetype1 == 3){prefix1 = "dices-";}
if (i <=15) {
document.getElementById("dice").src='http://localhost/CodeIgniter_2.1.2/dice/' + prefix1 + die_num1 + '.gif';
}
if (i >=15) {
document.getElementById("dice").src='http://localhost/CodeIgniter_2.1.2/dice/die-' + die_num1 + '.gif';
i=0;
}
}

Categories

Resources