I'm looking to nest a char-count value inside a HTML text area, just like the image below. I'm still a Js rookie so any advice is more than welcome. I have done some digging and haven't really come across anything that could really help me.
As I don't have access to the CSS or HTML files directly I have to target these elements through Js. My question is can something like the image below, be done completely in Js? If so where do I start?
The elements ID' is = 'desinp'
I'll include my current JsFiddle of what I have at this point in time.
To do this completely in JavaScript you have to change the HTML dynamically, and insert the proper elements in the correct places, and then add an event handler etc.
var wrapper = document.createElement('div');
var text = document.getElementById("desinp");
var c_wrap = document.createElement('div');
var count = document.createElement('span');
wrapper.style.position = 'relative';
c_wrap.style.position = 'absolute';
c_wrap.style.bottom = '8px';
c_wrap.style.color = '#ccc';
c_wrap.innerHTML = 'Char :';
text.parentNode.appendChild(wrapper);
wrapper.appendChild(text);
c_wrap.appendChild(count);
wrapper.appendChild(c_wrap);
text.style.color = "#ccc";
text.style.resize = "none";
text.style.height = "auto";
text.rows = "3";
function _set() {
c_wrap.style.left = (text.clientWidth - c_wrap.clientWidth - 12) + 'px';
count.innerHTML = this.value.length || 0;
}
text.addEventListener('input', _set);
_set.call(text);
<!-- textarea. -->
<textarea style="width: 364px; height: 149px;" class="required" id="desinp" name="desinp" maxlength="150"></textarea>
I have added a snippet of Javascript which would count the remaining characters, you can add up the characters if you want to show the total characters typed, you can design the element as per your need. The rest of code is from your fiddle.
// Char limit.
function maxLength(el) {
if (!('maxLength' in el)) {
var max = el.attributes.maxLength.value;
el.onkeypress = function() {
if (this.value.length >= max) return false;
};
}
}
maxLength(document.getElementById("desinp"));
document.getElementById('desinp').onkeyup = function () {
document.getElementById('count').innerHTML = "Characters left: " + (150 - this.value.length);
};
// Element style over-ride.
document.getElementById("desinp").style.color = "#ccc";
document.getElementById("desinp").style.resize = "none";
document.getElementById("desinp").style.height = "auto";
document.getElementById("desinp").rows = "3";
<!-- textarea. -->
<textarea style="width: 364px; height: 149px;" class="required" id="desinp" name="desinp" maxlength="150" ></textarea>
<span id="count"></span>
Related
Im new to JavaScript, I'm using vanilla js , html and css to survey website where user can add question, and option as well, when they click a button it will create a container which they can fill with the 'tag:textarea'. I'm using the 'createElement()', 'setAttribute()' method for creating a new container. But since each container has so many nested nodes or components, I have write a tons of boilerplate code to create a container, plus I have to change the id of some element with the nested 'Hell' , It become so hard to managed. My html code is Below:
<div id="create-question-container-id" class="create-question-container" >
<div id="create-question-textarea-container-id_0" class="create-question-textarea-container">
<textarea id="create-question-textarea-id"
name="textareaquestion" class="create-question-textarea"
cols="50" row="1" style="font-size: 20pt;">
Untitled Question
</textarea>
<div id="create-answer-textarea-container-id-0" class="create-answer-textarea-container">
<div id="create-answer-N-container-id-0-0" class="create-answer-N-container">
<div class="create-qeuestion-radio-outer-circle" >
<div class="create-qeuestion-radio-innner-circle"></div>
</div>
<textarea id="opt1" name="textareaopt" class="create-answer-textarea"
placeholder="opt1" style="font-size: 14pt;">
</textarea>
</div>
</div>
<button onclick="addOption()" class="create-add-answer-btn" >
Add Option
</button>
</div>
</div>
<div class="create-main-container-submit-button">
<button onclick="clonecontainer()" class="create-main-submit-btn" >
Submit
</button>
</div>
And this is the Javascript Code from hell:
var answer_container = document.getElementsByClassName('create-answer-textarea-container');
//increment this one
var answer_container_id = document.getElementById('create-answer-textarea-container-id-0');
var lastChildAnswer = answer_container[answer_container.length - 1];
var asnwer_container_list = answer_container_id.childNodes[answer_container.length];
//id of container wrapping around the question and the options named questionasnwcontain(this need to increment id)
var question_answer_container_list = document.getElementById('create-question-textarea-container-id_0')
//id of container wrapping around the questionasnwcontain(main container)
var all_question_asnwer_container = document.getElementById('create-question-container-id');
var all_question_asnwer_container_class_Name = document.getElementsByClassName('create-question-container');
var all_counter = all_question_asnwer_container.childElementCount -1;
function clonecontainer() {
var dashed_delimeter = '-';
var lastChildContainer = answer_container_id.lastElementChild.getAttribute('id')
var trimlastChild = answer_container_id.lastElementChild.lastElementChild.getAttribute('id')
var delimeter = 't'
var trimlastChildSubString = trimlastChild.split(delimeter);
var lastChildString = trimlastChildSubString[1]
//split lastChildContainer
var splitted_lastChildContainer = lastChildContainer.split(dashed_delimeter)[5];
var new_id_spliited_lastChildContainer = 'create-answer-N-container-id-' + ((parseInt(splitted_lastChildContainer)) + (all_question_asnwer_container.childElementCount -1) ) + '-0';
//get the cloned container's child id for incremental
var last_main_container_child = all_question_asnwer_container.lastElementChild.getAttribute('id');
var trimlast_id = seperateWithDelimeter(last_main_container_child);
var trimlast_new_id ='_' + (parseInt(trimlast_id[1]) + (all_question_asnwer_container.childElementCount -1) );
console.log(trimlast_new_id)
//(fixed)
var last_cloned_delimeter = '_';
var last_cloned_container = all_question_asnwer_container.childNodes[all_question_asnwer_container_class_Name.length].getAttribute('id')
var splitted_cloned_container = last_cloned_container.split(last_cloned_delimeter);
var new_splitted_cloned_container_id = 'create-answer-textarea-container-id-' + ((parseInt(splitted_cloned_container[1])) + (all_question_asnwer_container.childElementCount )) ;
console.log(new_splitted_cloned_container_id)
//new div fr asnwer container
var new_div_fr_answer_container_id = document.createElement('div');
new_div_fr_answer_container_id.setAttribute('class' , 'create-question-textarea-container');
new_div_fr_answer_container_id.setAttribute('id' ,'create-question-textarea-container-id' + trimlast_new_id)
console.log(new_div_fr_answer_container_id)
//new question text area
var new_textarea_fr_create_question_textarea_id = document.createElement('textarea');
new_textarea_fr_create_question_textarea_id.setAttribute('class' , 'create-question-textarea');
new_textarea_fr_create_question_textarea_id.setAttribute('id' , 'create-question-textarea-id')
new_textarea_fr_create_question_textarea_id.setAttribute('cols' , 50);
new_textarea_fr_create_question_textarea_id.setAttribute('row' , 1);
new_textarea_fr_create_question_textarea_id.style.fontSize = '20pt';
//new for option text area wrrapeer
var new_option_text_area_wrapper = document.createElement('div');
new_option_text_area_wrapper.setAttribute('class' , 'create-answer-textarea-container');
new_option_text_area_wrapper.setAttribute('id' , new_splitted_cloned_container_id);
var new_option_N_text_area_wrapper = document.createElement('div');
new_option_N_text_area_wrapper.setAttribute('class' , 'create-answer-N-container');
new_option_N_text_area_wrapper.setAttribute('id', new_id_spliited_lastChildContainer);
var new_checkbox_inner = document.createElement('div');
new_checkbox_inner.setAttribute('class' , 'create-qeuestion-radio-inner-circle');
//create Element for checkBox outerCircle
var new_checkbox = document.createElement('div');
new_checkbox.setAttribute('class' , 'create-qeuestion-radio-outer-circle');
//append innerCircle
new_checkbox.appendChild(new_checkbox_inner);
var new_answer = document.createElement('textarea');
new_answer.setAttribute('name' , 'textareaopt');
new_answer.setAttribute('id' , 'opt'+ (parseInt(lastChildString) + 1));
new_answer.setAttribute('class' , 'create-answer-textarea');
new_answer.setAttribute('placeholder' , 'opt'+ (parseInt(lastChildString) + 1))
new_answer.style.fontSize = "14pt";
new_option_N_text_area_wrapper.appendChild(new_checkbox);
new_option_N_text_area_wrapper.appendChild(new_answer);
new_option_text_area_wrapper.appendChild(new_option_N_text_area_wrapper);
new_div_fr_answer_container_id.appendChild(new_textarea_fr_create_question_textarea_id);
new_div_fr_answer_container_id.appendChild(new_option_text_area_wrapper);
all_question_asnwer_container.appendChild(new_div_fr_answer_container_id);
}
All of them are just the repetitive methods. So my question is, is there a more efficient way of doing this or is there like a class that I can use to make it more manageable.
You have several options, two of which are:
If you don't mind parsing HTML each time (and parsing HTML is really fast on modern browser), you can use insertAdjacentHTML instead, perhaps with a template literal so you can embed newlines easily and use ${x} syntax for embedded values:
all_question_asnwer_container.insertAdjacentHTML("beforeend", `<div>
(etc.)
</div>`);
You can use a template element in your HTML that you clone (via cloneNode) as needed. Here's the cloning part of MDN's example from the linked page
var tbody = document.querySelector("tbody");
var template = document.querySelector('#productrow'); // The template element
// Clone the new row and insert it into the table
var clone = template.content.cloneNode(true);
var td = clone.querySelectorAll("td");
td[0].textContent = "1235646565";
td[1].textContent = "Stuff";
tbody.appendChild(clone);
const
btAdd = document.querySelector('button#bt-add')
, container = document.querySelector('div#container')
, builder =
{ ref_id : 0
, newDiv()
{
let sub_id = 0
, div = document.createElement('div')
;
div.id = ++this.ref_id
div.innerHTML = `
<div id="bla-bla-id_${this.ref_id}" class="xxzw">
<em> text areas: </em><br>
<textarea id="opt${this.ref_id}-${++sub_id}" placeholder="txt-area ${this.ref_id}-${sub_id} "></textarea><br>
<textarea id="opt${this.ref_id}-${++sub_id}" placeholder="txt-area ${this.ref_id}-${sub_id} "></textarea>
</div>`
container.appendChild(div)
}
}
btAdd.onclick = e =>
{
builder.newDiv()
}
div#container {
margin : 1em;
width : 20em;
}
div#container > div {
margin : .8em 0;
padding : .2em;
border : 1px solid lightblue;
}
em {
font-size : .7em;
font-weight : bold;
}
textarea {
width : 90%;
}
<button id="bt-add">add</button>
<div id="container"> </div>
<div id="textLength" class="textLength"> Hello World !!!</div>
<script>
function testTextLength() {
var textL = document.getElementById("textLength").innerText;
var maxLength = 15;
if (textL.length > maxLength) {
textL.style.fontSize = "250%";
}
}
</script>
Please help me that font size of "Hello World !!!" should change after reaching the more than 15 characters.
You are setting the fontsize to the innertext. Set it to the element.
<div id="textLength" class="textLength"> Hello World !!!</div>
<script>
function testTextLength() {
var textL = document.getElementById("textLength");
var maxLength = 15;
if (textL.innerText.length > maxLength) {
textL.style.fontSize = "250%";
}
}
</script>
Here's what I would do. Change your div to an input:
<input id="textLength" class="textLength">
Then, bind an event to it, like 'keyup'. You need this so your JS knows when to check on the length of text entered.
<script>
var textL = document.getElementById("textLength");
textL.addEventListener('keyup',function(){
var maxLength = 15;
var txt = textL.value;
if (txt.length > maxLength) textL.style.fontSize = "250%";
});
</script>
Instead of 'keyup', you could also listen for 'keypress', 'keydown' or 'change'. In this case, I recommend using 'keyup'. Here's a working example:
https://jsfiddle.net/wxmvagL3/3/
If you want to reset the font size when the length goes below 15 chars, add an else block:
if (txt.length > maxLength) textL.style.fontSize = "250%";
else textL.style.fontSize = "100%";
I want to make java script function that makes new line when I press Enter key in input tag space.
Also I hope, when making new line, the height of input tag space dynamically stretches.
<!-- onkeydown function -->
function Enter(){
if(event.keyCode === 13){
var element = document.getElementById("PostingArea");
<!-- I don't know here -->
}
}
<!-- html code -->
<input class="PostingArea" id="PostingArea" onkeydown="Enter()">
You need to use textarea and indicate how many rows you expect, like this:
<textarea name="taText" cols="80" rows="25"></textarea>
Use textarea tag.using textarea multiple line text can be submitted.
Try this updated version
function onTestChange() {
var key = window.event.keyCode;
var el = document.getElementById("PostingArea");
var height = el.offsetHeight;
var newHeight = height + 20;
var value = el.val();
// If the user has pressed enter
if (key === 13) {
el.style.height = newHeight + 'px';
var newValue = value + '<br/>';
el.val(newValue)
return false;
}
if (event.keyCode == 8) {
el.style.height = newHeight - 'px';
var newValue = value - '<br/>';
el.val(newValue)
return false;
}
else {
return true;
}
}
<body>
<div id ="PostingArea" class="input-area" style="height:20px;" onkeypress="onTestChange()">
<input type="text" style="height:100%;" />
</div>
</body>
I am creating a tile based game using tables. In each td cell,
<td>
<div id="image" style="display:none; display: fixed; right: 5; top:2;"><img src="http://thumb7.shutterstock.com/display_pic_with_logo/339217/339217,1272881114,1/stock-vector-hand-drawing-of-typical-house-along-the-canal-near-bangkok-in-thailand-52242874.jpgAttap"/></div>
<input id ="attap" type="submit" value="Show Div" onclick="showDiv(); if(submitted)this.disabled = true" />
<div id="welcomeDiv" style="display:none;"> <input type="submit" name="answer" value="Show Div" onclick="showDiv3(); if(submitted)this.disabled = true" /></div>
<div id="welcomeDiv3" style="display:none;"> <input type="submit" name="answer" value="Show Div" onclick="showDiv4(); if(submitted)this.disabled = true"" /></div>
<div id= "welcomeDiv4" style="display:none;"><input type="submit" name="answer" value="Show Div" onclick="showDiv5(); if(submitted)this.disabled = true"" /> </div>
</td>
Javascipt:
function showDiv() {
document.getElementById('welcomeDiv').style.display = "block";
document.getElementById('image').style.display = "block";
submitted = true;
populationred +=20;
document.getElementById('population').innerHTML = populationred;
}
function showDiv3() {
document.getElementById('welcomeDiv3').style.display = "block";
document.getElementById("image").innerHTML = "'<img src='http://www.sgshophouses.com/images/Shophouses1.jpg'>'"
submitted = true;
populationred +=50;
document.getElementById('population').innerHTML = populationred;
}
function showDiv4() {
document.getElementById('welcomeDiv4').style.display = "block";
document.getElementById('image').innerHTML = "'<img src='http://singaporepropertylaunch.com.sg/wp-content/uploads/2015/04/HDB-resale-prices-fall-1.0.gif'>'"
submitted = true;
populationred +=100;
document.getElementById('population').innerHTML = populationred;
}
function showDiv5() {
document.getElementById('image').innerHTML = "'<img src='www.realestatechannel.com/assets_c/2010/06/Austonian-Condo-Tower-thumb- 120x238.jpg'>'"
submitted = true;
populationred +=200;
document.getElementById('population').innerHTML = populationred;
}
I need to repeat this for 144 cells. However, the problem is that when 1 button is clicked, the image will show up only at the first cell, hence the tedious way of solving this issue is to rename all the divs differently for every cell. Is there any more efficient ways?
You can refer here: www2.hci.edu.sg/t0104448b/cells.html for a "fiddle".
Shilly's comment had the right idea. I'm not entirely sure what your goal is but this is what I did, that looks reasonably what you're after. It should get you started.
There's only one click handler, on the <table> itself. It's effectively delegating the click. This saves memory because you're not creating a copy/closure for every cell. It costs some performance due to the delegating nature but for click handlers, it's generally okay. For mouseover handlers, that's another subject.
Using a <template> tag effectively gives you a DocumentFragment to work with and markup as HTML, instead of doing it in JavaScript (which can be tedious).
We clone that document fragment 144 times, injecting the proper description ('ShopHouse', 'HDB Flat', 'Condo', etc.) into each stamp of the template. Each clone is appended to a document fragment. Once our document fragment is done being modified, we inject it into the DOM via board.appendChild(frag);.
var board = document.getElementById('board');
var cellTmpl = document.getElementById('template-cell');
var cellTmplContent = cellTmpl.content;
var frag = document.createDocumentFragment(); // for performance
var submitted = false; // not sure what you intend to use this for
var descriptions = [ 'ShopHouse', 'HDB Flat', 'Condo' ]; // ... etc.
var cells = [];
for (var r = 0; r < 12; r++) {
var row = [];
cells.push(row);
var tr = document.createElement('tr');
frag.appendChild(tr);
for (var c = 0; c < 12; c++) {
var clone = document.importNode(cellTmplContent, true);
var index = r * 12 + c;
var description = index < descriptions.length ? descriptions[index] : 'Unknown place';
clone.querySelector('p.description').innerText = description;
tr.appendChild(clone);
row.push(clone);
}
}
board.appendChild(frag);
board.addEventListener('click', function(e) {
var button = e.target;
var td = button.parentElement;
var img = td.querySelector('img');
var p = td.querySelector('p.description');
button.disabled = true;
img.style.display = 'block';
p.style.display = 'block';
submitted = true;
});
// could do something with `cells` variable if you like. It's a two dimensional array of <td> elements
td {
background: #ccc;
border: 1px solid #000;
}
td > img {
display: none;
zoom: 0.2;
}
p.description {
display: none;
}
<table id="board">
</table>
<template id="template-cell">
<td>
<img src="http://thumb7.shutterstock.com/display_pic_with_logo/339217/339217,1272881114,1/stock-vector-hand-drawing-of-typical-house-along-the-canal-near-bangkok-in-thailand-52242874.jpgAttap"/>
<button>Show</button>
<p class="description"></p>
</td>
</template>
I'm trying to make a game that measures your reaction time, but my fastest score tracker is very buggy. It works during the first reaction test but after that stops working. Thanks in advance to anyone that can help.
<!DOCTPYE html>
<html>
<head>
<script>
window.onload = alert("Press START to start the game. As soon as the screen turns red click the stop button. Get the fastest time you can. Good luck");
var button = document.getElementById("reactionTester");
var start = document.getElementById("start");
var startTime;
var scoreContainer = document.getElementById("p");
var css = document.createElement("style");
css.type= "text/css";
var counter = 0;
var timer = null;
var highscore = document.getElementById("highscore");
var currentRecord = 0;
var highscoreCounter = 0;
function init(){
var startInterval/*in milliseconds*/ = Math.floor(Math.random()*10)*1000;
clearTimeout(timer);
timer = setTimeout(startTimer,1/*startInterval*/);
document.body.appendChild(css);
css.innerHTML = "html{background-color: blue;}";
}
function startTimer(){
startTime = Date.now();
css.innerHTML="null";
css.innerHTML = "html{background-color: red;}";
if(counter==1){
p1 = document.getElementsByTagName('p')[1];
p1.parentNode.removeChild(p1);
counter++;
}
}
function stopTimer(){
if(startTime){
var stopTime = Date.now();
var dif = stopTime - startTime;
alert("Your time is " + dif + " ms");
startTime = null;
css.innerHTML = null;
var p = document.createElement("p");
document.body.appendChild(p);
p.innerHTML = dif;
counter=1;
if (highscoreCounter != 0){
if(dif < currentRecord){
Phighscore2 = document.getElementsByTagName('p')[0];
Phighscore2.parentNode.removeChild(Phighscore2);
document.getElementById("highscore").appendChild(highscoreP);
currentRecord = dif;
highscoreP.innerHTML = currentRecord;
}
else{}
}
else{
var highscoreP = document.createElement("p");
document.getElementById("highscore").appendChild(highscoreP);
currentRecord = dif;
highscoreP.innerHTML = currentRecord;
highscoreCounter++;
}
}
else{
alert("don't trick me");
}
}
</script>
</head>
<body>
<div id="highscore">
</div>
<form id="form">
<div class="tableRow">
<input type="button" value="start" id="start" onclick="init()">
</div>
<div class="tableRow">
<input type="button" id="reactionTester" onclick="stopTimer()" value="stop">
</div>
<div id="p">
</div>
</form>
</body>
</html>
Your problem is caused by the fact that variable highscoreP is defined locally in function stopTimer. Local variables lose their value upon function return. Make it a global variable (and do not forget to remove its 'var' keyword inside the function).
I cannot resist making some additional remarks about your code:
Do not create the same DOM elements over and over again; it complicates your code and stresses out the browser's memory manager. Define all elements statically and refer to them by ID as you already did with the containers (highscore, p).
Do not build a style element dynamically, this is really bad practice. Instead, define CSS classes statically, then assign the classes dynamically by setting attribute className.
Even though you are doing a pretty good job programming in plain javascript, you may want to consider using jQuery.