I'm learning how to code javascript, please do not reply that this can be done by using someone else's code that already exists. I am doing this to learn.
I have a situation whereby the below CSS and HTML code:
CSS:
div.miniblock {
font-size: 12px;
background-color: #333333;
text-align: center;
vertical-align: middle;
border: thin dotted #CCCCCC;
color: #FFFFFF;
padding: 2px;
margin: 5px;
cursor: move;
position: relative;
}
div.miniblock_unsaved {
font-size: 12px;
background-color: #55AAAA;
text-align: center;
vertical-align: middle;
border: thin dotted #000;
color: #000;
padding: 2px;
margin: 5px;
cursor: move;
position: relative;
}
div.dropinto {
font-size: 12px;
background-color: #575757;
text-align: center;
vertical-align: middle;
border: thin dotted #AAAAAA;
color: #FFFFFF;
padding: 2px;
margin: 5px;
}
div.dropinto_over {
font-size: 12px;
background-color: #FFFFFF;
text-align: center;
vertical-align: middle;
border: thin dotted #000000;
color: #000000;
padding: 2px;
margin: 5px;
}
div.moving {
font-size: 12px;
background-color: #CCCCCC;
text-align: center;
vertical-align: middle;
border: thin dotted #000000;
color: #000000;
z-index:1;
height: 80px;
width: 80px;
opacity: 0.7;
padding: 5px;
cursor: move;
}
div.OPAQUE {
font-size: 12px;
background-color: #FFF;
text-align: center;
vertical-align: middle;
color: #000000;
opacity: 0.5;
}
HTML:
<INPUT TYPE="HIDDEN" NAME="block_side[3]" VALUE="" ID="block_side0">
<INPUT TYPE="HIDDEN" NAME="block_order[3]" VALUE="" ID="block_order0">
<INPUT TYPE="HIDDEN" NAME="block_side[4]" VALUE="" ID="block_side1">
<INPUT TYPE="HIDDEN" NAME="block_order[4]" VALUE="" ID="block_order1">
<INPUT TYPE="HIDDEN" NAME="block_side[5]" VALUE="" ID="block_side2">
<INPUT TYPE="HIDDEN" NAME="block_order[5]" VALUE="" ID="block_order2">
<INPUT TYPE="HIDDEN" NAME="block_side[6]" VALUE="" ID="block_side3">
<INPUT TYPE="HIDDEN" NAME="block_order[6]" VALUE="" ID="block_order3">
<INPUT TYPE="HIDDEN" NAME="block_side[2]" VALUE="L" ID="block_side=4">
<INPUT TYPE="HIDDEN" NAME="block_order[2]" VALUE="1" ID="block_order4">
<INPUT TYPE="HIDDEN" NAME="block_side[1]" VALUE="L" ID="block_side=5">
<INPUT TYPE="HIDDEN" NAME="block_order[1]" VALUE="2" ID="block_order5">
<DIV CLASS="OPAQUE" ID="instruct"></DIV>Set your preferences for the blocks of information and their display location here.<TABLE height="100%" width="100%"><TR ><TH COLSPAN="2">Assigned Blocks</TH></TR><TR ><TD COLSPAN="2">Here are the blocks that are currently displayed during your experience.</TD></TR><TR ><TD WIDTH="50%" VALIGN="TOP"><DIV CLASS="dropinto" ID="leftblocks" SLOT="L">Left Blocks<div onmousedown="grabobj(4)" onmousemove="dragobj(4)" onmouseup="dropobj(4)" id="4" name="2" class="miniblock">Quick Links [2]</div><div onmousedown="grabobj(5)" onmousemove="dragobj(5)" onmouseup="dropobj(5)" id="5" name="1" class="miniblock">Session Information [1]</div></DIV></TD><TD WIDTH="50%" VALIGN="TOP"><DIV CLASS="dropinto" ID="rightblocks" SLOT="L">Right Blocks</DIV></TD></TR><TR ><TH COLSPAN="2">Unassigned Blocks</TH></TR><TR ><TD COLSPAN="2" ID="unassigned_blocks">Here are the blocks that are not currently displayed during your experience.<div onmousedown="grabobj(0)" onmousemove="dragobj(0)" onmouseup="dropobj(0)" id="0" name="3" class="miniblock">Another Block [3]</div><div onmousedown="grabobj(1)" onmousemove="dragobj(1)" onmouseup="dropobj(1)" id="1" name="4" class="miniblock">And Another [4]</div><div onmousedown="grabobj(2)" onmousemove="dragobj(2)" onmouseup="dropobj(2)" id="2" name="5" class="miniblock">Poll Voting [5]</div><div onmousedown="grabobj(3)" onmousemove="dragobj(3)" onmouseup="dropobj(3)" id="3" name="6" class="miniblock">SysAdmin Block [6]</div></TD></TR></TABLE>
and the below Javascript:
window.instruct = function(id, instr){
var el = document.getElementById(id);
el.innerHTML = instr;
}
window.blockprefs = function(id, thisblock){
// determine which slot thisblock belongs to
s = id.getAttribute('SLOT');
// identify all the child nodes associated to this slot
c = id.childNodes;
for(var i=1;i < c.length; i++) { // I set i = 1 here because I don't care about the parent element at this time.
name = c[i].getAttribute('NAME');
// console.log(c.length,c[i]);
pos = document.getElementById('block_side'+name);
ord = document.getElementById('block_order'+name);
pos.setAttribute('VALUE',s);
ord.setAttribute('VALUE',i);
console.log(name,pos,ord,c[i]);
}
};
window.grabobj = function(id){
// console.log('moving object: '+id);
// console.log(document.getElementById(id));
// console.log(event.clientX+', '+event.clientY);
thisblock = document.getElementById(id);
thisblock.setAttribute('CLASS','moving');
thisblock.setAttribute('STATUS','click');
thisblock.style.position = 'absolute';
thisblock.style.left = event.pageX - 40;
thisblock.style.top = event.pageY - 20;
// id.addEventListener('mousemove',function(){console.log('moving mouse: x('+event.clientX)+') y('+event.clientY+')';},false);
};
window.drop = function(id, hit) {
id.setAttribute('STATUS','drop');
id.setAttribute('CLASS','miniblock_unsaved');
id.setAttribute('STYLE','');
instruct('instruct','You have unsaved changes, be sure to commit your changes below.');
};
window.dropobj = function(id){
thisblock = document.getElementById(id);
if(thisblock.getAttribute('STATUS') == 'drag' || thisblock.getAttribute('STATUS') == 'click'){
// determine if the block was dropped within one of the drop object targets
// if it was not, return it to the original location, otherwise, drop it into the new location
var left = document.getElementById("leftblocks"),
right = document.getElementById('rightblocks'),
leftbounds = left.getBoundingClientRect(),
rightbounds = right.getBoundingClientRect(),
t = window.pageYOffset || document.documentElement.scrollTop,
l = window.pageXOffset || document.documentElement.scrollLeft;
if(event.clientX >= leftbounds.left && event.clientX <= leftbounds.right && event.clientY >= leftbounds.top && event.clientY <= leftbounds.bottom){
// hit on the left blocks bounds, drop it into the left block
left.appendChild(thisblock);
//thisblock.insertBefore(left.firstchild);
drop(thisblock);
// now assign the hidden form element the correct values based on the current config in the left block then
// here is what I think will have to happen:
// identify all child nodes of the parent node
// identify all of the hidden form fields associated to those child nodes
// update all of the hidden form fields associated to those child nodes with
// the correct order and L / R flag.
// not sure how to complete those tasks at this time.
// console.log( document.getElementById('block_order' + thisblock.getAttribute('ID')));
// console.log( left.childElementCount );
blockprefs(left, thisblock);
} else if(event.clientX >= rightbounds.left && event.clientX <= rightbounds.right && event.clientY >= rightbounds.top && event.clientY <= rightbounds.bottom){
// hit on the right blocks bounds, drop it into the right block
right.appendChild(thisblock);
//thisblock.insertBefore(right.firstchild);
drop(thisblock);
// now assign the hidden form element the correct values based on the current config in the left block then
} else {
// user missed dropping into the left or right box, drop it back into unassigned.
var u = document.getElementById("unassigned_blocks");
u.appendChild(thisblock);
drop(thisblock);
}
}
};
window.dragobj = function(id){
thisblock = document.getElementById(id);
if(thisblock.getAttribute('STATUS') == 'click' || thisblock.getAttribute('STATUS') == 'drag'){
thisblock.style.left = event.pageX - 40;
thisblock.style.top = event.pageY - 20;
thisblock.setAttribute('STATUS','drag');
}
};
window.onload = function() {
// on mouseover change color of leftdiv or right div
var left = document.getElementById("leftblocks");
var right = document.getElementById('rightblocks');
console.log(left.nodeValue);
function block_over(block){ // set the attribute of the block on mouse over
// console.log('setting property of block: '+block);
block.setAttribute('CLASS','dropinto_over');
}
function block_out(block){ // set the attribute of the block on mouse out
block.setAttribute('CLASS','dropinto');
}
left.addEventListener('mouseover',function(){block_over(left); },true); // listener to set the left block's attributes
left.addEventListener('mouseout',function(){block_out(left); },true);
right.addEventListener('mouseover',function(){block_over(right); },true); // listener to set the right block's attributes
right.addEventListener('mouseout',function(){block_out(right); },true);
};
I attempted to put this into a JSFIDDLE https://jsfiddle.net/vt1hcLL6/ but the frames were throwing it off so it might have to just go into a flat html file sorry.
As a user, the intent of this code is to be able to pick up the blocks and move them into the slots (either the left or the right side) blocks, or remove them from those blocks.
After doing so, javascript will set some values in the hidden form fields so that upon saving the page php will grab those values.
Currently it's only setup to do so if you move a block into the left side and yes once I get this all nailed from a hardcoded perspective I will abstract it further, for now some of this is hard coded.
My problem is that upon the first instance of dropping a block into the Left Side Block, everything works fine all the HIDDEN form fields update correctly with the SLOT="L" Attribute and the ORDER="i" attribute (i being the number corresponding to the child iteration.
Great! It works! Now... once a second block is added to that set from down below, the code breaks and I can't figure out why.
The code that is performing this functionality is in the blockprefs( ) function where I iterate through all the child nodes of the Left block and attempt to bring in the hidden form elements belonging to each child. I get a:
divblock.js:33 Uncaught TypeError: Cannot read property 'setAttribute' of null
Related
I am trying to get user input and then print that number of boxes on the screen, I can get the boxes spawning if I do no checks and just set them to spawn whenever I click one, However, once I start adding in checks the boxes just stop spawning.
var count = 1;
function spawnBox() {
var container = document.getElementById("container");
var newBox = document.createElement("div");
newBox.className = "box";
newBox.innerHTML = count;
container.appendChild(newBox);
count++
}
function checkIfCanSpawn() {
while (count < inputNumber) {
spawnBox();
}
}
div.box {
width: 10vw;
height: 8vw;
background: rgb(8, 144, 168);
margin: 1vw;
float: left;
text-align: center;
font-size: 5vw;
padding-top: 1vw;
font-family: sans-serif;
}
<label id="type in a number" name="Input a number"> Type In a number </label>
<input id="inputNum" type="number" name="inputNumber"> </input>
Tweaked a little to make it work.
Added onchange event on input class.
then instead of using the count, i made use of the available while loop and passed the count instead.
then clear the "container" every run.
function spawnBox(count) {
// Get the container
var container = document.getElementById("container");
// Create a new div
var newBox = document.createElement("div");
newBox.className = "box";
newBox.innerHTML = count;
// Append it to the container
container.appendChild(newBox);
// Increment count
count++
}
function checkIfCanSpawn() {
document.getElementById("container").innerHTML = "";
var inputNumber = document.getElementById("inputNum").value;
var x = 1;
while (x <= inputNumber) {
spawnBox(x);
x++;
}
}
div.box {
width: 10vw;
height: 8vw;
background: rgb(8, 144, 168);
margin: 1vw;
float: left;
text-align: center;
font-size: 5vw;
padding-top: 1vw;
font-family: sans-serif;
}
<label id="type in a number" name="Input a number"> Type In a number </label>
<input id="inputNum" type="number" name="inputNumber" onchange="checkIfCanSpawn()" />
<div id="container"></div>
https://jsfiddle.net/Lqj4dktw/
Add a button with a click-eventHandler to call the spawnBox():
$(document).ready(function() {
$("#btn" ).click(function(){
let inputNumber = $("#inputNum").val();
while (count < inputNumber) {
spawnBox();
}
})
})
Her is a working fiddle
There are 5 boxes, which can be changed from 'white'<->'yellow' colors by mouse events (mouseover, mouseout and click). There is also a blue area with text displaying the level of the clicked box.
After clicking into the third box, I got 'hard level' text in blue area and 3 boxes color in yellow.
What I need is to return it to the default level ('easy level' and first box in yellow only) by clicking the reset button.
I have been trying do this like this , but it isn't working:
resetBtn = document.querySelector('#update');
and eventlistener:
resetBtn.addEventListener('click', highlightStars(`#star1`), true)
Here is an example:
window.addEventListener('DOMContentLoaded', changeStars, false);
const resetBtn = document.querySelector('#update');
/* Change level of the game depending on user choice */
function changeStars() {
/* Displaying level text inside blue box */
const updateAltText = currentLevelIndex => {
let levelText = document.querySelector('#level-text');
/* 'currentLevelIndex + 1' replaces event 'currentElement' */
levelText.textContent = document.querySelector(`#star${currentLevelIndex + 1}`).alt;
}
/* Captcha level number - default is 1 */
const getNumber = str => Number(str.match(/\d+/)[0]) || 1;
/* Star index is always one number lower than level number (indexing rules) */
const getStarIndex = event => getNumber(event.target.id) - 1;
let stars = document.querySelectorAll('.star');
const handleStarClick = event => {
/* FIRST - blocking possibility to change star behaviour by mouse events */
gameLevel.removeEventListener('mouseover', highlightStars);
gameLevel.removeEventListener('mouseout', highlightStars);
/* SECOND - making all needed star with yellow color */
const stars = document.querySelectorAll('.star');
for (let i = 0; i <= getStarIndex(event); i++) {
stars[i].classList.add('yellow');
}
};
const highlightStars = event => {
const starIndex = getStarIndex(event);
updateAltText(starIndex);
for (let i = 1; i <= starIndex; i++) {
const star = document.querySelector(`#star${i + 1}`);
star.classList.toggle('yellow');
}
};
// resetBtn.addEventListener('click', highlightStars(`#star1`), true);
resetBtn.addEventListener('click', updateAltText(0), true);
const gameLevel = document.querySelector('.game-level');
gameLevel.addEventListener("mouseover", highlightStars);
gameLevel.addEventListener("mouseout", highlightStars);
gameLevel.addEventListener('click', handleStarClick, {once: true});
}
.stars {
display: flex;
margin: 10px auto;
width: 500px;
}
input[type='image'] {
width: 60px;
height: 60px;
border: thin solid black;
}
.yellow {
background-color: yellow;
}
.game-level {
display: flex;
width: 300px;
height: 100%;
}
.level-block {
display: flex;
width: 200px;
margin-left: 10px;
justify-content: center;
align-items: center;
border: 1px solid hsl(217, 86%, 50%);
border-radius: 25px;
background-color: hsl(212, 29%, 80%);
}
.level-block > span {
font-size: 18px;
}
.reset {
width: 80px;
height: 80px;
}
<div class="stars">
<div class="game-level">
<input type="image" class="star yellow" id="star1" src="" width="60" alt="easy level">
<input type="image" class="star" id="star2" src="" width="60" alt="normal level">
<input type="image" class="star" id="star3" src="" width="60" alt="hard level">
<input type="image" class="star" id="star4" src="" width="60" alt="very hard level">
<input type="image" class="star" id="star5" src="" width="60" alt="impossible level">
</div>
<div class="level-block">
<span id="level-text">Easy level</span>
</div>
</div>
<input type="button" class="reset" id="update" value="RESET">
The following demo uses JavaScript for click events only, all mouse events (ie hover) are pure CSS. The reset behavior simply removes .active class on all buttons then adds .active class to the first button. Instead of the first button title being displayed after a reset -- the reset button title: "Game Reset" is displayed, it might be a little confusing for users if there's no confirmation of a reset. Other behavior is included in demo that is logical and consistent such as toggling, hovering to a temporary state and clicking for a persistent state etc. Details are commented in demo.
// Reference the form
const stars = document.forms.stars;
/*
Register the form to the click event -- when a click occurs anywhere on or within the form, callback function twinkle() is
called
*/
stars.onclick = twinkle;
/**
//A -- twinkle passes a reference to the Event Object... (e)
//B1 - Two Event Object properties are used to reference:
The tag the was clicked by user: event.target
The tag registered to the event: event.currentTarget
//B2 - The HTMLFormElement property: .elements collects all form
controls into a Live HTML Collection (aka NodeList)
//C -- ui.star is a Collection of form controls with [name=star]
The brackets [] and spread operator ... converts the
NodeList into an Array
//D -- Reference the message tag. If the clicked tag was the reset
button -- for...of loop iterates through each [name=star]
and removes the class .active from all [name=star]
//E1 - Next add .active class to the default button
//E2 - Set the legend.message text to the value of clicked button
[title] attribute...
~~~~~~~
//F -- ...But if a button.star was clicked, a check to verify if
clicked tag has the .active class -- then a for...of
loop identical to the one described in line D is used to
remove any .active class.
//G -- After there are no .active, the Boolean declared in line F
determines whether the clicked tag gets the .active class
and its [title] attribute displayed or not
*/
function twinkle(e) {
const active = e.target;
const ui = e.currentTarget.elements;
const starZ = [...ui.star];
const msg = document.querySelector(".message");
if (active.matches("#clear")) {
for (let star of starZ) {
star.classList.remove("active");
}
ui.star1.classList.add('active');
msg.textContent = active.title;
} else if (active.matches(".star")) {
let status = active.classList.contains("active");
for (let star of starZ) {
star.classList.remove("active");
}
if (!status) {
active.classList.add("active");
msg.textContent = active.title;
} else {
active.classList.remove("active");
msg.textContent = "";
}
}
return false;
}
:root {
font: 400 small-caps 2.5vw/1 Arial
}
.levels {
display: table;
width: 96%;
height: auto;
border: 1px solid hsl(217, 86%, 50%);
border-radius:4px;
}
.message {
display: table-caption;
width: 40vw;
height: 6vh;
margin: 0 auto 2vh;
padding: 0.5vh 0;
border: 1px solid hsl(217, 86%, 50%);
border-radius: 1.5rem;
background-color: hsla(212, 29%, 80%, 25%);
text-align: center;
font-size: 1.5rem;
color: #0078D7;
}
#clear {
float: right;
transform: rotate(45deg);
padding: 0;
border: none;
background: none;
font-size: 3.5rem;
cursor: pointer;
}
#clear:focus {
outline: 0;
}
/*
Flex is applied to the button.star'S parent tag so the order
property can be utilized.
*/
.flex {
display: flex;
justify-content: space-evenly;
align-items: center;
width: 70vw;
}
.star {
display: table-cell;
position: relative;
width: 16vw;
height: 24vh;
border: thin solid black;
background: #DDD;
font-size: 3.75rem;
text-align: center;
vertical-align: middle;
cursor: pointer;
}
/*
GSC (General Sibling Combinator: ~ ) provides highlighting across
multiple buttons.
Exp. 5 buttons: [-] [-] [X] ~ [>] ~ [>]
*/
.star.active,
.star:hover,
.star.active ~ .star,
.star:hover ~ .star {
background: gold;
}
/*
HTML layout has button.star in reverse order. Applying order to
each button rectifies the order by APPEARING in order while the
HTML structure remains reversed.
*/
#star1 {
order: 1;
border-top-left-radius: 6px;
border-bottom-left-radius: 6px;
}
#star2 {
order: 2;
}
#star3 {
order: 3;
}
#star4 {
order: 4;
}
#star5 {
order: 5;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
}
#star1:hover,
#star1.active {
color: #5BC0DE;
}
#star2:hover,
#star2.active {
color: #FF1C8D;
}
#star3:hover,
#star3.active {
color: #00D800;
}
#star4:hover,
#star4.active {
color: #0000D5;
}
#star5:hover,
#star5.active {
color: #D50000;
}
<form id="stars" action="">
<fieldset name="levels" class="levels">
<legend class="message">Novice</legend>
<button id="clear" type="reset" title="Game Reset">🔄</button>
<section class="flex">
<button id="star5" name='star' class="star" title="Master">🟐</button>
<button id="star4" name='star' class="star" title="Expert">🟌</button>
<button id="star3" name='star' class="star" title="Advanced">🟊</button>
<button id="star2" name='star' class="star" title="Intermediate">🟆</button>
<button id="star1" name='star' class="star active" title="Novice">🟂</button>
</section>
</fieldset>
</form>
(I have recreated it somewhat in the JSFiddle, keep in mind that it doesn't have any aesthetic visuals, its just basic to show and the <script> is also down below in the HTML code)
I have written this small function from bare bone, the basic behind it is that it should recreate a form (by adding classes in HTML from a function), which gives 4 correct check marks (the green ones) in the right corner, when they are all filled in, and 4 fault check marks (red marks) when they are not all filled in or none of them at all when the user hits send.
But now for example when a user fills in 3 of them but not one not, it will show an red check mark on all of them, how can I make it look like it only will show a redmark on the one that is not filled it, and even if he fills in the one that was not filled it it will not 'update' only when the user refreshes the page, how can I fix that?
Also how can I give a live update for example, when the user types in for example their name and moves on to the next text field which will be the subject then it should already show a greenmark for the name one, how can I fix that?
Thanks for all the effort and help in advance. (I know this form will never work since I need PHP for this.)
I think you are looking for this . See the below Snippet
jQuery('.notchecked').on('input', function() {
nietLeeg($(this));
});
function validateEmail(sEmail) {
var reEmail = /^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+#(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!\.)){0,61}[a-zA-Z0-9]?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/;
if (!sEmail.match(reEmail)) {
return false;
}
return true;
}
function nietLeeg(elem) {
if (elem == null) {
var elem = $('.notchecked');
}
elem.each(function() {
var $this = $(this);
if ($this.val() && $this.attr('id') != 'email') {
$this.removeClass('nochecked').addClass('checked');
} else if ($this.attr('id') == 'email' && validateEmail($this.val())) {
$this.removeClass('nochecked').addClass('checked');
} else {
$this.removeClass('checked').addClass('nochecked');
}
});
}
.contactmiddle>input[type="text"] {
background-color: black;
border: 1px solid white;
color: white;
margin-bottom: 10px;
height: 45px;
width: 100%;
border-radius: 5px;
padding-left: 5px;
}
.contactright>input[type="text"] {
background-color: black;
border: 1px solid white;
color: white;
width: 100%;
height: 103px;
margin-bottom: 10px;
border-radius: 5px;
padding-left: 5px;
}
.checked {
background-image: url("http://www.freeiconspng.com/uploads/check-mark-31.png");
background-size: 50px;
background-repeat: no-repeat;
background-position: right;
}
.nochecked {
background-image: url("http://www.falconpedia.de/images/6/63/No_check.png");
background-size: 50px;
background-repeat: no-repeat;
background-position: right;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<section class="contactmiddle">
<input class="notchecked" id="naam" name="contactpersoon" placeholder="Name" required="" type="text">
<input class="notchecked" id="email" name="contactpersoon" placeholder="Email" required="" type="text">
<input class="notchecked" id="subject" name="contactpersoon" placeholder="Subject" required="" type="text">
</section>
<section class="contactright">
<input class="notchecked" id="bericht" name="contactpersoon" placeholder="Message" required="" type="text">
<input class="knop" onclick="nietLeeg();" type="button" value="send">
</section>
You can add the follow Jquery/JS code :
function nietLeeg () {
var inputs = $('input');
inputs.each(function(){
var presentInput = $(this);
if(presentInput.val() == ''){
presentInput.removeClass('checked');
presentInput.addClass('nochecked');
}
else{
presentInput.addClass('checked');
presentInput.removeClass('nochecked');
}
});
};
$('input').on('blur',function(){
nietLeeg();
})
On every blue event the function will be called.
The function works in the following way :
if the input field is empty -> it will remove the checked class and add nochecked class. and vice versa for a non empty input field.
I have a fairly simple CSS question. I have an input text field, and on page load i would like it to be 150px in width.
However, as the user enters some text, if the text is greater than 150px in width, then the width should auto adjust.
Here's a plunker:
http://plnkr.co/edit/ig0BQrJDiEtXKV8zJ2w2?p=preview
HTML:
<input class="input-class" type="text" placeholder="Placeholder">
CSS:
.input-class-2 {
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
border-color: -moz-use-text-color -moz-use-text-color #ef8e80;
border-image: none;
border-style: none none dashed;
border-width: 0 0 1px;
color: #ef8e80;
cursor: pointer;
font-family: Gotham-Book;
font-size: 18px;
min-width: 150px;
}
I assumed min-width would do this.
There currently is no way to achieve this with pure CSS, perhaps once calc and attr can be used in combination, but not currently. So we have to fall back to JavaScript.
There isn't any real reason to use jQuery for this. You can argue that your "concerns should be separated" i.e. code should be separate from mark-up, but that is easy to do using addEventListener. However, if I'm dealing with one off small bits of JavaScript it tends to be faster — in terms of implementation, page render and even for those trying to track down what is making the input behave strangely — to use inline event listeners.
<input type="text"
style="min-width: 150px;"
onkeyup="this.size = Math.max(this.value.length, 1)"
/>
or:
<input type="text"
style="width: 150px;"
onkeyup="
this.style.width = '1px';
this.style.width = (
this.scrollWidth > 140
? this.scrollWidth + 10
: 150
)+'px';
"
/>
Disclaimer: Obviously if you are implementing many of these inputs it is far better to code a generalised function to handle them. Plus it is always far better to avoid inline style by using a stylesheet.
/**
* Directly setting the size attribute, with minWidth
*/
function autosize(elm, minWidth){
var keyup = function(e){
var t = e.target || e.srcElement;
var v = Math.max(t.value.length, 1);
t.setAttribute
? t.setAttribute('size', v)
: (t['size'] = v)
;
};
elm.style.minWidth = minWidth+'px';
elm.addEventListener
? elm.addEventListener('keyup', keyup)
: elm.attachEvent('onkeyup', keyup)
;
};
The size attribute is by far the most obvious choice, although you can directly set the width — if you prefer — using scrollWidth.
/**
* Directly setting width, with minWidth
*/
function autosize(elm, minWidth){
var keyup = function(e){
var t = e.target || e.srcElement;
t.style.width = '1px';
t.style.width = t.scrollWidth + 'px';
};
elm.style.minWidth = minWidth+'px';
elm.addEventListener
? elm.addEventListener('keyup', keyup)
: elm.attachEvent('onkeyup', keyup)
;
};
You can trigger either of these functions by passing your target element in as the first argument. There are a number of ways of finding your element, the easiest and most universal being getElementById. Although you will only be able to find your element if it has been parsed by the browser, so the script tag you use — to run the following code — will either have to be placed below the element in the mark-up i.e. bottom of <body> (preferable), or after waiting for window load, or DOM readiness.
autosize( document.getElementById('myinput'), 150 );
/**
* Directly setting width, with minWidth
*/
function autosize1(elm, minWidth){
var keyup = function(e){
var t = e.target || e.srcElement;
t.style.width = '1px';
t.style.width = t.scrollWidth + 'px';
};
elm.style.minWidth = minWidth+'px';
elm.addEventListener
? elm.addEventListener('keyup', keyup)
: elm.attachEvent('onkeyup', keyup)
;
};
/**
* Directly setting the size attribute, with minWidth
*/
function autosize2(elm, minWidth){
var keyup = function(e){
var t = e.target || e.srcElement;
var v = Math.max(t.value.length, 1);
t.setAttribute
? t.setAttribute('size', v)
: (t['size'] = v)
;
};
elm.style.minWidth = minWidth+'px';
elm.addEventListener
? elm.addEventListener('keyup', keyup)
: elm.attachEvent('onkeyup', keyup)
;
};
autosize1( document.getElementById('a'), 150 );
autosize2( document.getElementById('b'), 150 );
<p>Each input is using a different implementation:</p>
<input type="text"
style="min-width: 150px;"
onkeyup="this.size = Math.max(this.value.length, 1)"
/><br />
<input type="text"
style="width: 150px;"
onkeyup="
this.style.width = '1px';
this.style.width = (
this.scrollWidth > 140
? this.scrollWidth + 10
: 150
)+'px';
"
/><br />
<input type="text" id="a" /><br />
<input type="text" id="b" /><br />
You can try like this:
function resizeInput() {
$(this).attr('size', $(this).val().length);
}
$('input[type="text"]')
.keyup(resizeInput)
.each(resizeInput);
JSFIDDLE DEMO
There is one more alternative of using the
<span contenteditable="true">Some Text</span>
instead of using Input tags.
JSFIDDLE DEMO
You can try something like this
$('.input-class').keyup(function(){
var textlength=$('.input-class').val().length
$(this).width(textlength * 8)
})
.input-class{
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
border-color: -moz-use-text-color -moz-use-text-color #ef8e80;
border-image: none;
border-style: none none dashed;
border-width: 0 0 1px;
color: #ef8e80;
cursor: pointer;
font-family: Gotham-Book;
font-size: 18px;
min-width: 150px;
width:auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<input class="input-class" type="text" placeholder="Placeholder">
Tried to use pure JavaScript.
I hide a span element that's not shown (visibility:hidden;) to the user.
Then I calculate the span elements rendered width, and setting that to the container of the input.
And setting the input to be width:100%; makes it grow to the size of its parent.
var field = document.getElementById("grow");
field.oninput = function() {
var ruler = document.getElementById("ruler");
ruler.innerHTML = field.value.replace(/ /g," ");
var outer = document.getElementById("outer");
if (ruler.offsetWidth > 100) {
outer.setAttribute('style', "width:" + (ruler.offsetWidth + 5) + "px;");
} else {
outer.setAttribute('style', "");
}
};
#grow {
height: 100%;
width: 100%;
font-size: inherit;
font-family: inherit;
}
#outer {
width: 100px;
font-size: 1rem;
font-family: Serif, "Times New Roman", Georgia;
}
.hidden {
position: absolute;
display: inline;
visibility: hidden;
padding: 0;
font-size: inherit;
font-family: inherit;
white-space: nowrap;
}
<div id="outer">
<span id="ruler" class="hidden"></span>
<input id="grow" type="text/plain"/>
</div>
<p>+ Expands</p>
<p>+ shrinks</p>
<p>+ whitespace handling</p>
I am trying to format a number input by the user into currency using javascript. This works fine on <input type="text" />. However, on <input type="number" /> I cannot seem to be able to set the value to anything that contains non-numeric values. The following fiddle shows my problem
http://jsfiddle.net/2wEe6/72/
Is there anyway for me to set the value to something like $125.00?
I want to use <input type="number" /> so mobile devices know to bring up a keyboard for number input.
Add step="0.01" to the <input type="number" /> parameters:
<input type="number" min="0.01" step="0.01" max="2500" value="25.67" />
Demo: http://jsfiddle.net/uzbjve2u/
But the Dollar sign must stay outside the textbox... every non-numeric or separator charachter will be cropped automatically.
Otherwise you could use a classic textbox, like described here.
In the end I made a jQuery plugin that will format the <input type="number" /> appropriately for me. I also noticed on some mobile devices the min and max attributes don't actually prevent you from entering lower or higher numbers than specified, so the plugin will account for that too. Below is the code and an example:
(function($) {
$.fn.currencyInput = function() {
this.each(function() {
var wrapper = $("<div class='currency-input' />");
$(this).wrap(wrapper);
$(this).before("<span class='currency-symbol'>$</span>");
$(this).change(function() {
var min = parseFloat($(this).attr("min"));
var max = parseFloat($(this).attr("max"));
var value = this.valueAsNumber;
if(value < min)
value = min;
else if(value > max)
value = max;
$(this).val(value.toFixed(2));
});
});
};
})(jQuery);
$(document).ready(function() {
$('input.currency').currencyInput();
});
.currency {
padding-left:12px;
}
.currency-symbol {
position:absolute;
padding: 2px 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input type="number" class="currency" min="0.01" max="2500.00" value="25.00" />
You guys are completely right numbers can only go in the numeric field. I use the exact same thing as already listed with a bit of css styling on a span tag:
<span>$</span><input type="number" min="0.01" step="0.01" max="2500" value="25.67">
Then add a bit of styling magic:
span{
position:relative;
margin-right:-20px
}
input[type='number']{
padding-left:20px;
text-align:left;
}
It seems that you'll need two fields, a choice list for the currency and a number field for the value.
A common technique in such case is to use a div or span for the display (form fields offscreen), and on click switch to the form elements for editing.
I did using this . This code snippet automatically format numbers into currency and prefix a dollar sign.
<div class="main">
<h1>Auto Formatting Currency</h1>
<form method="post" action="#">
<label for="currency-field">Enter Amount</label>
<input type="text" name="currency-field" id="currency-field" pattern="^\$\d{1,3}(,\d{3})*(\.\d+)?$" value="" data-type="currency" placeholder="$1,000,000.00">
<button type="submit">Submit</button>
</form>
<p>Auto format currency input field with commas and decimals if needed. Text is automatically formated with commas and cursor is placed back where user left off after formatting vs cursor moving to the end of the input. Validation is on KeyUp and a final validation is done on blur.</p>
<p>To use just add the following to an input field:</p>
<pre>data-type="currency"</pre>
</div><!-- /main -->
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
background: #f5f5f5;
color: #333;
font-family: arial, helvetica, sans-serif;
font-size: 32px;
}
h1 {
font-size: 32px;
text-align: center;
}
p {
font-size: 20px;
line-height: 1.5;
margin: 40px auto 0;
max-width: 640px;
}
pre {
background: #eee;
border: 1px solid #ccc;
font-size: 16px;
padding: 20px;
}
form {
margin: 40px auto 0;
}
label {
display: block;
font-size: 24px;
font-weight: bold;
margin-bottom: 10px;
}
input {
border: 2px solid #333;
border-radius: 5px;
color: #333;
font-size: 32px;
margin: 0 0 20px;
padding: .5rem 1rem;
width: 100%;
}
button {
background: #fff;
border: 2px solid #333;
border-radius: 5px;
color: #333;
font-size: 16px;
font-weight: bold;
padding: 1rem;
}
button:hover {
background: #333;
border: 2px solid #333;
color: #fff;
}
.main {
background: #fff;
border: 5px solid #ccc;
border-radius: 10px;
margin: 40px auto;
padding: 40px;
width: 80%;
max-width: 700px;
}
// Jquery Dependency
$("input[data-type='currency']").on({
keyup: function() {
formatCurrency($(this));
},
blur: function() {
formatCurrency($(this), "blur");
}
});
function formatNumber(n) {
// format number 1000000 to 1,234,567
return n.replace(/\D/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ",")
}
function formatCurrency(input, blur) {
// appends $ to value, validates decimal side
// and puts cursor back in right position.
// get input value
var input_val = input.val();
// don't validate empty input
if (input_val === "") { return; }
// original length
var original_len = input_val.length;
// initial caret position
var caret_pos = input.prop("selectionStart");
// check for decimal
if (input_val.indexOf(".") >= 0) {
// get position of first decimal
// this prevents multiple decimals from
// being entered
var decimal_pos = input_val.indexOf(".");
// split number by decimal point
var left_side = input_val.substring(0, decimal_pos);
var right_side = input_val.substring(decimal_pos);
// add commas to left side of number
left_side = formatNumber(left_side);
// validate right side
right_side = formatNumber(right_side);
// On blur make sure 2 numbers after decimal
if (blur === "blur") {
right_side += "00";
}
// Limit decimal to only 2 digits
right_side = right_side.substring(0, 2);
// join number by .
input_val = "$" + left_side + "." + right_side;
} else {
// no decimal entered
// add commas to number
// remove all non-digits
input_val = formatNumber(input_val);
input_val = "$" + input_val;
// final formatting
if (blur === "blur") {
input_val += ".00";
}
}
// send updated string to input
input.val(input_val);
// put caret back in the right position
var updated_len = input_val.length;
caret_pos = updated_len - original_len + caret_pos;
input[0].setSelectionRange(caret_pos, caret_pos);
}
https://codepen.io/akalkhair/pen/dyPaozZ
The browser only allows numerical inputs when the type is set to "number". Details here.
You can use the type="text" and filter out any other than numerical input using JavaScript like descripted here