Using multiple selectors? - javascript

So I wrote this to take a button and recreate it as an Link with spans inside. However, I cant seem to get this to work for multiple buttons. I end up needing to copy and past the JS and enter in the different classes duplicating the entire script. There has to be an easier way to do this... Any thoughts?
Example of two buttons, and the only working solution thus far...
http://jsfiddle.net/En72J/5/
HTML
<div class="DIV_ONE">
<input type="button" class="INPUT_ONE" value="Today's Work Items 10" onclick="hAction_win1(document.win1,'CU_APPL_SUM_WRK_PERFORM_WEEKS', 0, 0, 'This Week\'s Items 10', false, true);" tabindex="16" name="CU_APPL_SUM_WRK_DATE_SEL_DAYS">
</div>
JQuery
// Page First loads Input Button Wrapped in Div.
// Grab Input Buttons Numbers ( Last 2 Characters )
var number = $('.INPUT_ONE').val().substr(-2);
// Grab Input Buttons Text, Minus the Numbers.
var term = $('.INPUT_ONE').val().slice(0, -2);
// Grab Input Buttons OnClick Value
var script = $('.INPUT_ONE').attr("onclick");
// Append 'term' Float Left
$('.DIV_ONE').append('<span class="text">' + term + '</span>');
// Append 'number' Float Right
$('.DIV_ONE').append('<span class="number">' + number + '</span>');
// Wrap Both 'term' and 'number' in an <A> LINK and set OnClick with 'script' var.
var second = $('.DIV_ONE').wrapInner('');
// Finally, Delete old Button. New <A> Link as Victor!
$('.INPUT_ONE').remove();
CSS
.btn_style {
border-bottom: 1px dotted #CCCCCC;
color: #666666;
display: block;
font-family: verdana;
font-size: 12px;
overflow: auto;
text-decoration: none;
}
.number {
background: none repeat scroll 0 0 #72716E;
color: #FFFFFF;
display: block;
float: right;
font-weight: bold;
padding: 4px;
position: relative;
width: 20px;
}
.text {
float: left;
padding: 4px;
}

Consider using a second class name to identify the elements you wish to process, then loop through them like so:
<div class="DIV_ONE buttonMe">
<input type="button" class="INPUT_ONE" value="Today's Work Items 10" onclick="hAction_win1(document.win1,'CU_APPL_SUM_WRK_PERFORM_WEEKS', 0, 0, 'This Week\'s Items 10', false, true);" tabindex="16" name="CU_APPL_SUM_WRK_DATE_SEL_DAYS">
</div>
JS:
$('.buttonMe').each(function() {
current= $(this);
// at this point "current" points to the outer DIV
currentInput = $(this).find('input')
// then you can manipulate the current input
})
Then you can treat "currentInput" as if it were the hard-coded element reference you're currently using in your code.

A simple loop would solve that :
$('input[class^="INPUT_"]').each(function() {
var n = $('<span />', {'class':'number', text : this.value.slice(-2)}),
t = $('<span />', {'class':'text', text : this.value.slice(0,-2)}),
a = $('<a />', {'class':'btn_style', onclick : $(this).attr('onclick')});
$(this).closest('div').append(a.append(n,t)).end().remove();
});
FIDDLE

You could select all inputs of type button by using
$('input:button').each( function(index) {
//do work here
});
and go through each button on your page.

create a seperate function and call the function with a selector for any number of inputs and div
function createlink(input, div) {
// Page First loads Input Button Wrapped in Div.
// Grab Input Buttons Numbers ( Last 2 Characters )
var number = $(input).val().substr(-2);
// Grab Input Buttons Text, Minus the Numbers.
var term = $(input).val().slice(0, -2);
// Grab Input Buttons OnClick Value
var script = $(input).attr("onclick");
// Append 'term' Float Left
$(div).append('<span class="text">' + term + '</span>');
// Append 'number' Float Right
$(div).append('<span class="number">' + number + '</span>');
// Wrap Both 'term' and 'number' in an <A> LINK and set OnClick with 'script' var.
var second = $(div).wrapInner('');
// Finally, Delete old Button. New <A> Link as Victor!
$(input).remove();
}
createlink('.INPUT_ONE', '.DIV_ONE');
createlink('.INPUT_TWO', '.DIV_TWO');
fiddle here

Use JQuery's $(this) and JQuery's .each.
Here's a working fiddle: http://jsfiddle.net/4jqBj/
HTML:
<div class="item">
<input type="button" class="item_btn" value="Today's Work Items 10" tabindex="16" />
</div>
<div class="item">
<input type="button" class="item_btn" value="This Week's Items 22" tabindex="16" />
</div>
JQUERY:
$(".item_btn").each(function () {
var number = $(this).val().substr(-2);
var term = $(this).val().slice(0, -2);
$(this).parent().append('<span class="text">' + term + '</span>').append('<span class="number">' + number + '</span>');
$(this).parent().wrapInner('');
$(this).remove();
});

Related

Attaching keydown event listener on div in contenteditable parent div not working?

Here's the parent div:
<div
id="comment"
placeholder="Your comment"
class="form-control ellipsesDropdown"
contenteditable="true"
#input="CommentChanged($event)"
> <!-- comments are divided into spans and divs with spans containg normal text and divs containing tags -->
<span>​</span>
</div>
Now when a user clicks a Tag, I create the Tag as follows:
const newTag = document.createElement('div');
newTag.setAttribute("tabindex", "-1");
newTag.style.cssText = "background-color: rgba(29,155,209,0.1); color: #1264a3; display: inline-block; font-weight: bold;";
const tagContent = document.createTextNode(`#${p}`); // imagine p is an input argument
newTag.append(tagContent);
// attach on key down event listener
newTag.onkeydown = function(event) {
console.log(event)
};
// add tag to the comment div
document.getElementById("comment")!.appendChild(newTag);
However, I get nothing when I press keys in the tag div, click events do work though. I took a look at How can I use a 'keydown' event listener on a div? and have added the tabindex attribute.
I've also tried attaching the event listener as:
newTag.addEventListener('keydown', function(event) {
console.log(event);
});
But this still doesn't work.
Any idea about what's going on?
EDIT: As requested, here's a codesandbox link: https://codesandbox.io/s/blue-bird-tdidr
EDIT 2: I've added more code from my project that basically implements to a certain extent what I'm trying to accomplish. Think about Twitter/Instagram/Slack, when you #someone as you're typing the post then perhaps some options appear for who to # and when you click someone then that "tag" is added to your post. In the example, go ahead and write something, and include #, you'll see a list of options open, click either bread or toast and see it become a tag. What I'm trying to do it add the on keydown EventListener on the Tag so go ahead and see that it doesn't work!
I see you want to create a comment function i guess? But the way you do its not the Vue.js way. Here is a simple comment box example:
let el = new Vue({
el: "#app",
template: "",
data(){
return {
comment: "",
comments: []
}
},
methods: {
addComment(){
let txt = this.convertTags(this.comment);
console.log(txt);
var d = new Date();
var n = d.toLocaleTimeString();
this.comments.push({
commentText: txt,
time: n
});
this.comment = "";
},
clickedTag(tag){
console.log(tag);
},
convertTags(str){
let strArr = str.split(" ");
let mappedArr = strArr.map(el => {
if(el.includes("#")){
el = `<span onclick='el.clickedTag("${el.replace("#", "")}")' class='tag'>${el}</span>`;
}
return " " +el;
});
this.template = mappedArr.join("")
return this.template;
}
}
});
#app {
width: 80%;
margin: 0 auto;
}
.comment {
background: #6c5ce7;
width: 100%;
margin: 5px 0;
color: white;
padding: 8px 5px;
}
input {
margin: 0 auto;
width: 100%;
display: block;
padding: 5px;
}
.tag {
color: black;
background: white;
padding: 2px;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="comment in comments" class="comments">
<div class="comment">
<p v-html="comment.commentText"></p>
<small>{{ comment.time }}</small>
</div>
</div>
<input type="text" v-model="comment" #keyup.enter="addComment">
</div>
Apparently I don't need to add an event listener to the divs I'm adding. I can just set their contenteditable attribute to false as user SleepWalker menstions in his answer here: How to delete an HTML element inside a div with attribute contentEditable?
So my answer would then become:
...
newTag.setAttribute("contenteditable", "false")
document.getElementById("comment")!.appendChild(newTag);
This allows me to delete the tag in one go!

Duplicating a division with child elements and buttons

I'm new to stack overflow so sorry if I don't articulate my problems well or show my code properly. working on a homework assignment where I have to create a game like the classic mastermind one. I have designed the game board and have created a 'round 1' division with toggling color buttons, submit button, and even calls up the proper result image (combination of white & black dots as img png).
My js code for duplicating the rounds is below. my problem is duplicating the round and all the functionality 9 more times. I would like to disable the toggle color buttons of a round once it is submitted and I would need to assign a new id to both the title of the round as well as the div where the result image would appear (since that changes with each new guess). But no matter what I try (generate all the code as string and append to body) the best I can get is 10 rounds but only functionality with round 1. All classes and Ids are same so the same event handlers and jQuery links should apply, yes?
Any-who, any help or suggestion is appreciated (thanks).
script code for creating rounds-
const nextRound = '
<div id="Round" class="level">
<h3 class="title"></h3>
<div class="buttondisplay">
<a id="boxa" class="button" class="active"></a>
<a id="boxb" class="button" class="active"></a>
<a id="boxc" class="button" class="active"></a>
<a id="boxd" class="button" class="active"></a>
</div><a id="submit" class="submitter">SUBMIT</a>
<div id="res1" class="results"></div>
</div>';
const buildRounds = () => { for (i = 1; i <= 10; i++){
$('#Gameboard').append(nextRound); }
}
The elements I would want to apply new ids are the boxa, boxb, boxc, and boxd, as well as the 'submit' and res1 (for resultsimage.png). Have been banging my head trying to make this work. Any help would be great. Or if you need more of the code, I can provide.
Thanks!
Rick
Issue
ids must be unique per page. You have a total of 6 different ids and each of those ids has 10 duplicates. jQuery/JavaScript will expect only one #Round or it expects one #boxc so once it finds an id it stops there and all the other duplicates are ignored or worse not entirely ignored. Basically when you have more than one element sharing an id, you will most likely get undesirable results if any at all. So you must make each id unique and a common way to do that is to assign a number to each id during a loop (i.e. "Round"+i)
BTW an element cannot have any duplicate attributes as well. So
<a id="boxd" class="button" class="active"></a>
is invalid and most likely the class='button' will be overwritten by class='active'. For multiple classes on a single element the syntax is:
<a id="boxd" class="button active"></a>
Details are commented in demo
Verify that all ids are unique by inspecting the page with DevTools.
Added Demo 2 which uses String Literals instead of Template Literals. IE does not support Template Literals hence Demo 2.
Demo 1 -- Using Template Literals
// Pass a number of rounds (i.e. 'qty')
function buildRounds(qty) {
/* Declare 'i' with 'let' limits i to only what
|| applies within the scope of the 'for' loop.
|| This limit helps 'i' to increment properly
|| without the influence of references outside
|| of the loop.
*/
for (let i = 1; i <= qty; i++) {
/* Use ES6 Template Literals* for complex strings
|| by wrapping the whole string with backticks `.
|| What is seen in code is literally rendered so
|| new lines are NOT ignored and escaping quotes
|| like this: `\'`or `\"` is not needed.
|| ${variable} is an interpolation of a value
|| inserted into the string. Note that the value 'i'
|| will be different on each loop therefore
|| ensuring unique ids.
*/
const nextRound = `
<div id="round${i}" class="level">
<h3 class="title">Round ${i}</h3>
<div class="buttonDisplay">
<a id="boxA${i}" class="button">A</a>
<a id="boxB${i}" class="button">B</a>
<a id="boxC${i}" class="button">C</a>
<a id="boxD${i}" class="button">D</a>
</div>
<a id="submit${i}" class="submitter">SUBMIT</a>
<div id="result${i}" class="results"></div>
</div>
`;
$('#gameBoard').append(nextRound);
}
/* Added function will toggle the '.active' class on/off
|| on each clicked '.button'. I don't know exactly what
|| good a "status" class would be if on every button,
|| so I changed it so now it can be toggled by user
*/
$('.button').on('click', function() {
$(this).toggleClass('active');
});
}
/* Call buildRounds() and pass the number
|| of rounds desired.
*/
buildRounds(10);
/* * Template Literals are not supported by M$ browsers
|| (i.e. IE). See Demo 2
*/
.button,
.submitter {
display: inline-block;
border: 3px ridge blue;
padding: 0 5px;
margin: 10px 5px;
color: blue;
cursor: pointer;
}
.button.active {
border: 3px inset red;
outline: 2px solid tomato;
color: red;
}
<main id='gameBoard'></main>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Demo 2 -- Using + to concat strings.
function buildRounds(qty) {
for (let i = 1; i <= qty; i++) {
/* This portion of the code is modifed to the use
|| of string literals instead of template literals.
|| If IE support is needed, then use this version.
*/
const nextRound = '<div id="round' + i + '" class ="level"><h3 class="title"> Round ' + i + ' </h3><div class="buttonDisplay"><a id="boxA' + i + '" class="button">A</a><a id="boxB' + i + '" class="button">B</a><a id="boxC' + i + '" class="button">C</a><a id="boxD' + i + '" class="button">D</a></div><a id="submit' + i + '" class="submitter">SUBMIT</a><div id="result' + i + '" class = "results"></div></div>';
$('#gameBoard').append(nextRound);
}
$('.button').on('click', function() {
$(this).toggleClass('active');
});
}
buildRounds(10);
.button,
.submitter {
display: inline-block;
border: 3px ridge blue;
padding: 0 5px;
margin: 10px 5px;
color: blue;
cursor: pointer;
}
.button.active {
border: 3px inset red;
outline: 2px solid tomato;
color: red;
}
<main id='gameBoard'></main>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

How to hide dynamically created html element with a dynamic ID

I have a dynamically created html elements under a for loop in JavaScript, these dynamic elements also has a dynamic id, my question is how can I hide the dynamically created elelment with a dynamic id. Thank you.
This is my code so far. I want to target the dynamic id and hide it.
product_list += '<div class="plProductContainer hide" data-pids="' + a_data.products[i].pid + '" id="'+a_data.products[i].pid+'">';
It has a dynamic id.
I would recommend you will use classes instead of id, but for this example you could use something like this. hide the element using a class.
$(document).ready(function(){
$(function(){
$(".add-more").on("click", function(){
var list = $(".list");
var random_id = Math.floor(Math.random() * (99999 - 1 + 1)) + 1;
var child = document.createElement("li");
var text = document.createTextNode("Lorem Ipsum");
child.setAttribute("id", random_id);
child.appendChild(text);
list.append(child);
});
});
$(function(){
$(".list").on("click", "li", function(){
var id = $(this).attr("id");
$("#" + id).addClass("hidden");
console.log("This id: " + id + " is hidden");
});
});
});
a{
color: blue;
cursor: pointer;
}
ul{
margin-top: 20px;
padding: 0;
}
li{
list-style: none;
cursor: pointer;
}
li:hover{
color: red;
}
li + li{
margin-top: 20px;
}
li.hidden{
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<div>
<a class="add-more">Click me!</a>
</div>
<ul class="list">
<li id="0">Lorem Ipsum</li>
</ul>
document.getElementById(a_data.products[i].pid).style.display = 'none';
Let me assume that you are using jquery. Try something like this:
$(".plProductContainer.hide").hide();
or
var elementId = $(".plProductContainer.hide").attr("id");
$("#"+elementId).hide();
or
If your element is inside another element with id someId, then:
$("#"+someId).children()[i].hide(); //i is the loop counter that you have used to create element dynamically
or
$("#"+a_data.products[i].pid).hide(); //i is the loop counter that you have used to create element dynamically
It becomes easier if you already know the values of you loop counter i.e value of i, if you don't know that then you can also use selectors like nth child. Let me know if any of the above works, else I'll put up more selectors.

Dynamically Adjust HTML Text Input Width to Content

I can't quite find a clear answer on this, and excuse me if there is one I've missed.
I want my text input widths to automatically adjust to the size of the content within them. First with placeholder text than the actual text someone inputs.
I've created the below as an example. Currently, the boxes are far bigger than my placeholder text, causing huge amounts of white space, and it's obviously the same thing when I type in something.
I've tried width auto, some jQuery, and twine and bubble gum I found on the internet. But nothing has worked yet. Any thoughts? Thanks!
HTML:
<span><p>Hello, my name is </p></span>
<span><input type="text" id="input" class="form" placeholder="name"></span>
<span><p>. I am </p></span>
<span><input type="text" id="input" class="form" placeholder="age"></span>
<span><p> years old.</p></span>
CSS:
.form {
border: 0;
text-align: center;
outline: none;
}
span {
display: inline-block;
}
p {
font-family: arial;
}
Fiddle
One possible way:
[contenteditable=true]:empty:before {
content: attr(placeholder);
color:gray;
}
/* found this online --- it prevents the user from being able to make a (visible) newline */
[contenteditable=true] br{
display:none;
}
<p>Hello, my name is <span id="name" contenteditable="true" placeholder="name"></span>. I am <span id="age" contenteditable="true" placeholder="age"></span> years old.</p>
Source for CSS: http://codepen.io/flesler/pen/AEIFc.
You'll have to do some trickery to pick up the values if you need the values for a form.
Use onkeypress even
see this example :http://jsfiddle.net/kevalbhatt18/yug04jau/7/
<input id="txt" placeholder="name" class="form" type="text" onkeypress="this.style.width = ((this.value.length + 1) * 8) + 'px';"></span>
And for placeholder on load use jquery and apply placeholder
size in to input
$('input').css('width',((input.getAttribute('placeholder').length + 1) * 8) + 'px');
Even you can use id instead of input this is just an example so that I
used $(input)
And in css provide min-width
.form {
border: 1px solid black;
text-align: center;
outline: none;
min-width:4px;
}
EDIT:
If you remove all text from input box then it will take placeholder value using focusout
Example: http://jsfiddle.net/kevalbhatt18/yug04jau/8/
$("input").focusout(function(){
if(this.value.length>0){
this.style.width = ((this.value.length + 1) * 8) + 'px';
}else{
this.style.width = ((this.getAttribute('placeholder').length + 1) * 8) + 'px';
}
});
input.addEventListener('input', event => event.target.style.width = event.target.scrollWidth + 'px');
Unfortunately this will only increase the size of the input. If you delete characters the size will not decrease. For some use cases this is perfectly fine.
Kevin F is right, there is no native way to do it.
Here is a one way to do it if you really want it to happen.
In the code, there is an invisible span where the text is placed. Then we retrieve the width of the span.
https://jsfiddle.net/r02ma1n0/1/
var testdiv = $("#testdiv");
$("input").keydown( function(){
var ME = $(this);
//Manual Way
//var px = 6.5;
//var txtlength = ME.val().length;
//$(this).css({width: txtlength * px });
testdiv.html( ME.val() + "--");
var txtlength = testdiv.width();
ME.css({width: txtlength });
});
Try with 'size' attribute.
This will work even when you clear the text .
Need jQuery to work this
<div>
<input id="txt" type="text" style="max-width: 100%;" placeholder="name">
</div>
<script>
$(document).ready(function() {
var placeholderLen = $('#txt').attr('placeholder').length;
// keep some default lenght
placeholderLen = Math.max(5, placeholderLen);
$('#txt').attr('size', placeholderLen);
$('#txt').keydown(function() {
var size = $(this).val().length;
$(this).attr('size', Math.max(placeholderLen, size));
});
});
</script>

html text field to have pre appended text which is not modifiable

I would like to have a text field which has pre appended text which is not modifiable.
So when user tries to add text it starts after the pre text.
Also when the form is submitted it should not pass the pre appended text. Its mainly for display purpose but within the text field. I have attached the image which will clarify my question further. For example I would like to add "$" as pre text in the image below. Any help is greatly appreciated.
Note: the $ is dynamic text and so could not be image.
I've made a fiddle with two solutions, both using CSS.
The first uses a data URI of a PNG that contains a dollar sign for the background image of the text input. The second uses a label containing a dollar sign and shifts it over to be on top of the input (you probably should use a span instead of a label, for accessibility's sake).
HTML:
<input type="text" id="bob" />
<br/>
<label for="fred">$</label><input type="text" id="fred" />
CSS:
#bob {
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgBAMAAACBVGfHAAAAG1BMVEX///8AAAC/v7/f398/Pz8fHx9/f3+fn59fX19QuZN1AAAAbElEQVQokWNgGFyASRiN7ygYhiKgGCYW6IAs4KgsYCqELCDKLMCehCwQyCyAamhjM5qAiaC4AqpIiaAoqgizuKMQqoAAuwgytxxoiyiSABvQHcwoKgSVBVjEkI1IlEDzCzu6bxnQnY4pQFsAAC/cCbAPkBI2AAAAAElFTkSuQmCC') no-repeat;
background-size: contain;
padding-left: 1.1em;
}
label[for="fred"] {
position: relative;
left: 15px;
z-index: 1000;
font-size: smaller;
}
#fred {
padding-left: 1.2em;
}
Both of these methods are hacky. A JS solution would be more involved, but handle much more nicely (I just don't have time to implement one).
Here's a neat way using background-image
http://jsfiddle.net/dxu2s/1/
HTML:
<label for="RefundAmount">Enter a refund amount: </label>
<input type="text" name="RefundAmount" id="RefundAmount">
CSS:
#RefundAmount {
margin: 0;
padding: 0 0 0 25px;
width: 100px;
height: 25px;
background: #FFF url(http://oi57.tinypic.com/nmncz5.jpg) no-repeat left center;
}
I've also tried using the css psuedo-element :before but it didn't work as input tags doesn't have content in em'.
This is a class i wrote you can use it for free, i didnt test it a lot. if you find a bug let me know
HTML: <input type="text" id="inputA" value="$" />
in script add this Class constructor
//***************************************************************
//-------------------------------------- Class halfEditable_INPUT
//***************************************************************
//-- divides an Input into an non editable area from 0 to index, but not including the index, the rest is editable
//-----------------------------------------------------
//-------- constructor
//-----------------------------------------------------
function halfEditable_INPUT (inputField,index)
{
if (typeof index=="undefined") index=inputField.value.length;
//------------------------------------ PUBLIC Objects, Properties
this.element=inputField;
this.index=index;
//-- a reference to the instance of the halfEditable_INPUT class saved in the html element, to get instance values in DOM events
Object.defineProperty (inputField,"halfEditable_instance",{value:this,writable: false, enumerable:true, configurable:true});
//-- get the value of the input directly
Object.defineProperty (this,"value", {get:this.PRIVATE_getValue,set:this.PRIVATE_setValue});
inputField.addEventListener ("keydown",this.PRIVATE_checkStatus_ONKEYDOWN);
}
//-----------------------------------------------------
//-------- prototype
//-----------------------------------------------------
//------------------------------------ PRIVATE Methods
/* this --- points to the input field
checks if the cursorPosition is in the non Editable area or is at the limit Point
if it is at the limitPoint - dont allow backspace or cursor left
if it is inside allow nothing and move cursorPosition to the limit
reset the Position1 key to index */
halfEditable_INPUT.prototype.PRIVATE_checkStatus_ONKEYDOWN=function (event)
{
var keyCode=event.keyCode;
var index=this.halfEditable_instance.index;
var selectionStart=this.selectionStart, selectionEnd=this.selectionEnd;
if (keyCode==36) //-- position1 key
{
event.preventDefault();
this.setSelectionRange (index,index);
return;
}
if (selectionStart<index)
{
if (selectionEnd>index) this.setSelectionRange (index,selectionEnd);
else this.setSelectionRange (index,index);
}
else if (selectionStart==index) {if (keyCode==8 || keyCode==37) event.preventDefault();} //-- backspace, left cursor
}
halfEditable_INPUT.prototype.PRIVATE_setValue=function (value) {this.element.value=value;}
halfEditable_INPUT.prototype.PRIVATE_getValue=function () {return this.element.value;}
//-----------------------------------------------------
//-------- prototype -- END
//-----------------------------------------------------
//***************************************************************
//-------------------------------------- Class halfEditable_INPUT -- END
//***************************************************************
var inputA=new halfEditable_INPUT(document.getElementById ("inputA"));
if you have further questions let me know.

Categories

Resources