Prevent .appendChild from creating inside already filled div? - javascript

I am trying to create a tic tac toe game where you can play against Math.floor(Math.random()) playing as O, with user is playing as X. But when I click, it sometimes creates O in an already filled box.
I just want to allow one P tag per div.
WARNING: code extremely messy and over complicated(sorry).
html:
<body onload="createDivs()">
<p id="demo"></p>
</body>
css:
div {
border: solid 2px black;
width: 300px;
height: 300px;
float: left;
border-right: none;
border-top: none;
overflow: hidden;
}
JavaScript:
var alternate = "O";
var count = 0;
function createDivs() {
var t;
var ai;
var trackId = [];
for (i = 0; i < 9; i++) {
var d = document.createElement("DIV");
document.body.appendChild(d);
d.onclick = function() {
if (count > 8) {
return
}
var xP = document.createElement("P");
var oP = document.createElement("P");
var childCount = "childID" + count;
xP.setAttribute("id", childCount);
trackId.push(childCount);
/*
alert(trackId.toString());
*/
count++;
oP.setAttribute("id", "childID" + count);
count++;
if (alternate == 'O') {
t = document.createTextNode("X");
alternate = 'X';
xP.appendChild(t);
this.appendChild(xP);
this.onclick = function() {};
/*
for (aa = 0; aa < 9; aa++) {
var zed = "D"+aa;
var bb = document.getElementById(zed).innerText;
while (bb == 'X' || bb == 'O') {
zed = Math.floor(Math.random() * 9);
}
}
*/
if (count > 9) {} else {
while (zed == 'X' || zed == 'O') {
var r = Math.floor(Math.random() * 9);
var zed = document.getElementById("D" + r).innerHTML;
var zob = "D" + r;
document.getElementById("demo").innerHTML = testConcat;
}
ai = document.createTextNode("O");
alternate = 'O';
oP.appendChild(ai);
d.appendChild(oP);
}
}
}
var ii = document.createAttribute("id");
ii.value = "D" + i;
d.setAttributeNode(ii);
var z = "D" + i;
if (i == 3 || i == 6) {
document.getElementById(z).style.clear = "left";
}
}
}

There were few issues in the code but the main problem was that when you are looking for the next empty slot, you are checking if the innerHTML of the Div is equal to "X" or "O". You can not use this logic since you are appending the p tag inside the div which has "X" or "O" as text.
So when you do document.getElementById("D"+r).innerHTML inside the while loop you will either get empty(this will work for you) or one of
<p>X</p>
<p>O</p>
(this will start causing problem) as this will make the code to append the child again on the same Div.
You should better check for the child elements inside a Div and if there is already a child element(slot is already filled) , code should look for another empty slot.
here is the updated code snippet
function createDivs() {
var t;
var ai;
var trackId =[];
var count = 0;
var alternate = "O";
for (i=0; i<9; i++) {
var d = document.createElement("DIV");
document.body.appendChild(d);
d.onclick = function() {
if (count > 8) {
return
}
var xP = document.createElement("P");
var oP = document.createElement("P");
var zed = "X";
var zod;
var childCount = "childID"+count;
xP.setAttribute("id", childCount);
trackId.push(childCount);
/*
alert(trackId.toString());
*/
count++;
oP.setAttribute("id", "childID"+count);
count++;
if (alternate == 'O') {
t = document.createTextNode("X");
alternate = 'X';
xP.appendChild(t);
this.appendChild(xP);
this.onclick = function() {};
if (count > 9) {
}
else
{
while (zed == 'X' || zed == 'O')
{
var r = Math.floor(Math.random() * 9);
if(document.getElementById("D"+r).childElementCount == 0)
zed = "";
zob = "D"+r;
}
ai = document.createTextNode("O");
alternate = 'O';
oP.appendChild(ai);
document.getElementById(zob).appendChild(oP);
}
}
}
var ii = document.createAttribute("id");
ii.value = "D" + i;
d.setAttributeNode(ii);
var z = "D" + i;
if (i == 3 || i == 6) {
document.getElementById(z).style.clear = "left";
}
}
}
Plunker : http://plnkr.co/edit/FgQ5KbNEvBpnag9mn9qO?p=preview
Hope this will help you.

If you want to add jQuery you could do that with if ($(this).find("p").length == 0)
Here as a jsfiddle

Related

How do I fix JS so the text isn't erased and continues to build up?

I like the idea of this code that creates a "typing effect" on my site, however I don't know how to edit JS very well. I'd like the text to be typed on but not be erased. I'd also like the cursor to remain blinking at the end.
I've fixed some of the CSS to my liking, but I've provided it in case it's necessary to complete the effect.
/***Javascript****/
<
script type = "text/javascript" >
// function([string1, string2],target id,[color1,color2])
consoleText(['Divi Notes.', 'Divi Tips and Tricks', 'Made with Love.'], 'text', ['#BD6983', 'tomato', 'lightblue']);
function consoleText(words, id, colors) {
if (colors === undefined) colors = ['#fff'];
var visible = true;
var con = document.getElementById('console');
var letterCount = 1;
var x = 1;
var waiting = false;
var target = document.getElementById(id)
target.setAttribute('style', 'color:' + colors[0])
window.setInterval(function() {
if (letterCount === 0 && waiting === false) {
waiting = true;
target.innerHTML = words[0].substring(0, letterCount)
window.setTimeout(function() {
var usedColor = colors.shift();
colors.push(usedColor);
var usedWord = words.shift();
words.push(usedWord);
x = 1;
target.setAttribute('style', 'color:' + colors[0])
letterCount += x;
waiting = false;
}, 1000)
} else if (letterCount === words[0].length + 1 && waiting === false) {
waiting = true;
window.setTimeout(function() {
x = -1;
letterCount += x;
waiting = false;
}, 1000)
} else if (waiting === false) {
target.innerHTML = words[0].substring(0, letterCount)
letterCount += x;
}
}, 120)
window.setInterval(function() {
if (visible === true) {
con.className = 'console-underscore hidden'
visible = false;
} else {
con.className = 'console-underscore'
visible = true;
}
}, 400)
} <
/script>
#import url(https://fonts.googleapis.com/css?family=Khula:700);
.hidden {
opacity:0;
}
.console-container {
font-family:Khula;
font-size:4em;
text-align:center;
height:30px;
width:600px;
display:inline;
position:relative;
color:black;
top:0;
bottom:0;
left:0;
right:0;
margin:auto;
}
.console-underscore {
display:inline-block;
position:relative;
left:10px;
}
#media (max-width: 750px) {
.console-container { font-size:2em; }
}
<div class='console-container'><span id='text'></span><div class='console-underscore' id='console'>_</div></div>
Expected results above, current results can be seen here: https://divinotes.com/typing-text-effect-using-divi-code-modules/
I don't know if i get your idea ... but you can change the case witch is erasing the text.
else if (letterCount === words[0].length + 1 && waiting === false) {
waiting = true;
window.setTimeout(function() {
x = -1;
letterCount += x;
waiting = false;
}, 1000)
}
The second problem is that it only renders one word at a time... If you want to have more words in different colors at the same moment, you should not write into innerHTML of the target element... Instead create child Elements of that tag and change only the active one....
<script type = "text/javascript" >
// function([string1, string2],target id,[color1,color2])
consoleText(['Divi Notes.', 'Divi Tips and Tricks', 'Made with Love.'], 'text', ['#BD6983', 'tomato', 'lightblue']);
function consoleText(words, id, colors) {
if (colors === undefined) colors = ['#fff'];
var visible = true;
var con = document.getElementById('console');
var letterCount = 1;
var x = 1;
var waiting = false;
var target = document.getElementById(id)
var textElement = document.createElement('span'); //a variable to store the active one
target.appendChild(textElement); // we append the textElement to the target
textElement.setAttribute('style', 'color:' + colors[0]) //instead of modifying target we modify textElement
window.setInterval(function() {
if (letterCount === 0 && waiting === false) {
waiting = true;
textElement.innerHTML = words[0].substring(0, letterCount)
window.setTimeout(function() {
var usedColor = colors.shift();
colors.push(usedColor);
var usedWord = words.shift();
// You can remove the repeating by uncommenting the following line
words.push(usedWord);
x = 1;
textElement.setAttribute('style', 'color:' + colors[0])
letterCount += x;
waiting = false;
}, 1000)
} else if (letterCount === words[0].length + 1 && waiting === false) { // erase case
waiting = true;
window.setTimeout(function() {
letterCount = 0; // start with a new word
textElement.innerHTML += " "; // apend a space to the old one to get seperation
textElement = document.createElement('span'); // create a new textElement for the next word
target.appendChild(textElement); // and append the new element to the target
waiting = false;
}, 1000)
} else if (waiting === false) {
textElement.innerHTML = words[0].substring(0, letterCount)
letterCount += x;
}
}, 120)
window.setInterval(function() {
if (visible === true) {
con.className = 'console-underscore hidden'
visible = false;
} else {
con.className = 'console-underscore'
visible = true;
}
}, 400)
} </script>
You can remove the repeating by uncommenting the following line
words.push(usedWord); This line adds the active word back to the words Queue.

why TypeError: par.getAttribute is not a function

I need change style's in <div> from {align, left} to {align, right}
function changeAttribute() {
var gg = document.getElementsByTagName("div");
var allP = gg[12].childNodes;
var par, align;
for (i = 0; i < allP.length; i++) {
par = allP[i];
gAl = par.getAttribute("align");
if (!gAl) {
continue
} else if (gAl == "right") {
align = par.setAttribute("align", "left");
}
align = par.setAttribute("align", "right");
}
}
Seems like your missing an else statement in the end.
align always gets set "right".
var gg = document.getElementsByTagName("div");
var allP = gg[12].childNodes;
var par, align;
for (i = 0; i < allP.length; i++){
par = allP[i];
if (gAl.nodeType !== Node.ELEMENT_NODE) continue;
gAl = par.getAttribute("align");
if(!gAl){
continue
} else if ( gAl == "right"){
align = par.setAttribute("align", "left");
} else {
align = par.setAttribute("align", "right");
}
}

char counter doesn't work with paste event

I have written a code bellow for counting the character inside text box.
the code is working just fine the only problem with it is when i past a text into the text box i have to press any key so system start to count.
Could you please help me sort this problem
function GetAlhpa(text) {
var gsm = "#£$¥èéùìòÇØøÅåΔ_ΦΓΛΩΠΨΣΘΞ^{}\[~]|€ÆæßÉ!\"#¤%&'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà";
var i = 0;
while (i <= String(text).length) {
if (gsm.indexOf(String(String(text).charAt(i))) == -1 && (String(text).charCodeAt(i) != 32) && (String(text).charCodeAt(i) != 27) && (String(text).charCodeAt(i) != 10) && (String(text).charCodeAt(i) != 13)) {
UniCodestring = " Unicode ";
Countsms = 70;
if ($('#SndSms_Message').val().length > 70)
Countsms = 67;
return;
}
i++;
}
Countsms = 160;
UniCodestring = "";
if ($('#SndSms_Message').val().length > 160)
Countsms = 153;
}
var Countsms = 160;
var UniCodestring = "";
var CounterSmsLen = 0;
var Two = "|^€{}[]~";
function GetCountSms() {
document.getElementById('SndSms_Message').addEventListener('input', function (e) {
var target = e.SndSms_Message,
position = SndSms_Message.selectionStart;
ConvertGreek();
CounterSmsLen = $('#SndSms_Message').val().length;
GetAlhpa($('#SndSms_Message').val());
var i = 0;
while (i < String(Two).length) {
var oldindex = -1;
while (String($('#SndSms_Message').val()).indexOf(String(String(Two).charAt(i)), oldindex) > -1) {
//if ( String($('#SndSms_Message').val()).indexOf(String(String(Two).charAt(i))) > -1){
CounterSmsLen += 1;
oldindex = String($('#SndSms_Message').val()).indexOf(String(String(Two).charAt(i)), oldindex) + 1;
console.log(i);
}
i++;
}
SndSms_Message.selectionEnd = position; // Set the cursor back to the initial position.
});
if ($('#SndSms_Message').val().length == 0)
CounterSmsLen = 0;
$('#SndSms_Count').html(' ' + CounterSmsLen + ' Characters' + UniCodestring + ' <br /> ' + Math.ceil(CounterSmsLen / Countsms) + ' Sms');
countsmsnumber=Math.ceil(CounterSmsLen / Countsms);
}
var greekchar = "ΑΒΕΖΗΙΚΜΝΟΡΤΥΧ";
var englishchar = "ABEZHIKMNOPTYX";
function ConvertGreek() {
var str = $('#SndSms_Message').val();
var i = 0;
while (i < String(greekchar).length) {
str = str.replace(new RegExp(String(greekchar).charAt(i), 'g'), String(englishchar).charAt(i));
i++;
}
$('#SndSms_Message').val(str);
P.S.
If i paste the number into the text box it will count it correct but if i paste character it wont count them..
You need keyup change event in order to handle paste event.
document.getElementById('SndSms_Message').addEventListener("keyup", function() {
//your code here
});
example

How to use AJAX or JSON in this code?

I am creating a website application that allows users to select a seat, if it is not already reserved, and reserve it.
I have created a very round about way of getting the seats that are previously reserved using iFrames, however that was temporarily, now I need to make it secure and "proper javascript code" using proper practices. I have no clue what AJAX (or JSON) is, nor how to add it to this code, but it needs to get the file "seatsReserved"+this.id(that is the date)+"Que.html" and compare the string of previously reserved seats to see which class to make the element. If this is horrible, or if any of the other things could work better, I am open to criticism to everything. Thank you all!
Here is the javascript code:
A little side note, all of the if statements are due to different amount of seats in each row
<script>
var i = " 0 ";
var counter = 0;
var leng=0;
document.getElementById("Show1").addEventListener("click", changeDay);
document.getElementById("Show2").addEventListener("click", changeDay);
document.getElementById("Show3").addEventListener("click", changeDay);
function changeDay() {
var iFrame = document.getElementById("seatList");
iFrame.src = "seatsReserved" + this.id + "Que.html";
document.getElementById('date').innerHTML = this.id;
var seatsTaken = iFrame.contentWindow.document.body.innerHTML;
var k = 0;
let = 'a';
var lc = 0;
for (lc = 1; lc <= 14; lc++) {
if (lc == 1) {
leng = 28;
}
else if (lc == 2) {
leng = 29;
}
else if (lc == 3) {
leng = 32;
}
else if (lc == 4 || lc == 6 || lc == 12 || lc == 14) {
leng = 33;
}
else if (lc == 5 || lc == 13) {
leng = 34;
}
else if (lc == 8 || lc == 10) {
leng = 35;
}
else {
leng = 36;
}
for (k = 1; k <= leng; k++) {
if (seatsTaken.indexOf((" " +
let +k + " ")) <= -1) {
seat = document.getElementById(let +k);
seat.removeEventListener("click", selectedSeat);
}
else {
document.getElementById(let +k).className = "openseat";
document.getElementById(let +k).removeEventListener("click", doNothing);
}
}
let = String.fromCharCode(let.charCodeAt(0) + 1);
}
}
function loadChanges() {
var iFrame = document.getElementById("seatList");
var seatsTaken = iFrame.contentWindow.document.body.innerHTML;
var k = 0;
let = 'a';
var lc = 0;
var leng = 0;
for (lc = 1; lc <= 14; lc++) {
if (lc == 1) {
leng = 28;
}
else if (lc == 2) {
leng = 29;
}
else if (lc == 3) {
leng = 32;
}
else if (lc == 4 || lc == 6 || lc == 12 || lc == 14) {
leng = 33;
}
else if (lc == 5 || lc == 13) {
leng = 34;
}
else if (lc == 8 || lc == 10) {
leng = 35;
}
else {
leng = 36;
}
for (k = 1; k <= leng; k++) {
if (seatsTaken.indexOf((" " +
let +k + " ")) <= -1) {
seat = document.getElementById(let +k);
seat.addEventListener("click", selectedSeat);
seat.className = "openseat";
}
else {
document.getElementById(let +k).className = "notAvailible";
document.getElementById(let +k).addEventListener("click", doNothing);
}
}
let = String.fromCharCode(let.charCodeAt(0) + 1);
}
i = " 0 ";
counter = 0;
document.getElementById("seatString").innerHTML = i;
document.getElementById("getSeats").value = i;
document.getElementById("seatnums").innerHTML = counter;
}
i = document.getElementById("seatString").innerHTML;
counter = document.getElementById("seatnums").innerHTML;
function selectedSeat() {
var w = this.id;
var l = (" " + w);
var b = (" " + w + " ");
if (counter < 5) {
if (i.indexOf(b) <= 0) {
this.className = "closedseat";
i = i + b;
i = i.replace(" 0 ", " ");
document.getElementById("seatString").innerHTML = i;
document.getElementById("getSeats").value = i;
counter = counter + 1;
document.getElementById("seatnums").innerHTML = counter;
}
else if (i.indexOf(b) > 0) {
this.className = "openseat";
i = i.replace(b, "");
document.getElementById("seatString").innerHTML = i;
document.getElementById("getSeats").value = i;
counter = counter - 1;
document.getElementById("seatnums").innerHTML = counter;
}
}
else if (i.indexOf(b) > 0) {
this.className = "openseat";
i = i.replace(b, "");
document.getElementById("seatString").innerHTML = i;
document.getElementById("getSeats").value = i;
counter = counter - 1;
document.getElementById("seatnums").innerHTML = counter;
}
}
function doNothing() {
}
var rannum = Math.random() * 1000;
document.getElementById('getConfirmation').value = rannum;
</script>

Javascript not working in Grails

I have a simple script works fine in html. Yet in a gsp, it doesn't work anymore.
My script is very simple, as below:
// program variables
var displayElement;
// constants
var maxLength = 300;
// calculator variables
var text;
var currentLength;
var dotPosition;
var lastNumber;
var currentNumber;
var rememberedNumber;
var operator;
alert('hello22');
function parseNumber(number) {
if ((number == -1) && (dotPosition > 0) || (maxLength == currentLength)) return;
if (currentLength == 0) text = '';
currentLength++;
if (number == -1) {
text += '.';
dotPosition = currentLength;
} else text += number;
displayElement.value = text;
}
function parseBackspace() {
if (currentLength == 0) return;
if ('.' == text[currentLength-1]) dotPosition = 0;
text = text.slice(0, currentLength-1);
if(--currentLength == 0) text = '';
displayElement.value = text;
}
function parseClearEntry() {
currentLength = 0;
text = '0';
dotPosition = 0;
displayElement.value = text;
}
function parseClear() {
parseClearEntry();
lastNumber = 0;
operator = '';
//added by Kevin
displayElement.value = '';
}
function initAll() {
alert('hello1113333333');
text = '0';
currentNumber = 0;
currentLength = 0;
displayElement = document.getElementById('TextBox');
rememberedNumber = 0;
lastNumber = 0;
dotPosition = 0;
alert('hello1111111111');
}
When I included into the gsp view page, I put <g:javascript src="getKey.js" /> between the <head></head>.
Then I call the function initAll() like <body onload="initAll()">, and others like <div class="holder"><input type="button" class="buttonstyle" value="7" name="Seven" onclick="parseNumber(7)" /></div>
Can anyone tell me what's wrong? I am sure the script has been included correctly because the alert "hello22" was threw.
Try to put somewhere following code at the footer:
<g:script>
(function() { initAll(); })();
</g:script>
or
<g:script>
window.onload = initAll; //note that is's without braces
</g:script>
instead of <body onload="initAll"

Categories

Resources