I was searching for autocomplete examples in pure javascript, and I found a pretty good example on JSFiddle, but it has a Bug that I'm trying to figure it out how to fix.
The autocomplete only autocompletes the text if you click at the paragraph twice
Code:
var db = [
"drawLine",
"drawCircle",
"drawCircleMore",
"fillLine",
"fillCircle",
"fillCircleMore"
];
function popupClearAndHide() {
autocomplete_result.innerHTML = "";
autocomplete_result.style.display = "none";
}
function updPopup() {
if (!autocomplete.value) {
popupClearAndHide();
return;
}
var a = new RegExp("^" + autocomplete.value, "i");
for (var x = 0, b = document.createDocumentFragment(), c = false; x < db.length; x++) {
if (a.test(db[x])) {
c = true;
var d = document.createElement("p");
d.innerText = db[x];
d.setAttribute("onclick", "autocomplete.value=this.innerText;autocomplete_result.innerHTML='';autocomplete_result.style.display='none';");
b.appendChild(d);
}
}
if (c == true) {
autocomplete_result.innerHTML = "";
autocomplete_result.style.display = "block";
autocomplete_result.appendChild(b);
return;
}
popupClearAndHide();
}
autocomplete.addEventListener("keyup", updPopup);
autocomplete.addEventListener("change", updPopup);
autocomplete.addEventListener("focus", updPopup);
#autocomplete {
border: 1px solid silver;
outline: none;
margin: 0;
background: #fff;
}
#autocomplete_result {
border: 1px solid silver;
border-top: 0;
position: absolute;
overflow: auto;
max-height: 93px;
background: #fff;
}
#autocomplete,
#autocomplete_result {
width: 200px;
box-sizing: border-box;
}
#autocomplete,
#autocomplete_result p {
padding: 4px;
margin: 0;
color: #000;
}
#autocomplete_result p:nth-child(2n+1) {
background: #f6f6f6;
}
#autocomplete_result p:hover {
background: #e5e5e5;
}
<input id="autocomplete" type="text" />
<div id="autocomplete_result" style="display: none;"></div>
On change event is trigger before the click event can complete
Removing the on change call would fix the issue. Great suggestion from the comment below by 'imvain2' to replace "keyup" event listener with "input" event listener. This would trigger on any input, not only "keyup".
Demo: https://jsfiddle.net/hexzero/qrwgh7pj/
autocomplete.addEventListener("input", updPopup);
autocomplete.addEventListener("focus", updPopup);
Related
The expected result is that when you click on each panel, the panel you clicked on moves, then moves back when you click it again.
The result with my current code is that no matter which panel you click it is always panel4 that toggles.
The reason these need to be added dynamically to each is because this list of panels will be auto populated and have the target ids dynamically generated too.
The Code....
var plbelements = document.getElementsByClassName("panel");
for (var l = 0; l < plbelements.length; l++) {
targetPanel = document.getElementById(plbelements[l].id);
actionSwipeAmount = "160px";
console.log("Target Panel before event listener = " + targetPanel.id);
targetPanel.addEventListener("click", (e) => {
left = window.getComputedStyle(targetPanel).getPropertyValue("left");
console.log(targetPanel.id);
if (left != actionSwipeAmount) {
targetPanel.style.left = actionSwipeAmount;
} else {
targetPanel.style.left = "0px";
}
});
}
body {
margin: 0;
}
.panelsContainer {
display: block;
max-width: 360px;
width: 100%;
min-height: 50px;
border: 1px solid black;
box-sizing: border-box;
overflow: hidden;
position: relative;
}
.underPanel {
display: block;
width: 360px;
min-height: 50px;
border: 1px solid black;
background-color: #6c6c6c;
color: white;
padding: 5px;
box-sizing: border-box;
position: relative;
color: white;
}
.panel {
display: block;
width: 360px;
min-height: 50px;
border: 1px solid black;
background-color: #141414;
color: white;
padding: 5px;
box-sizing: border-box;
position: absolute;
right: 0px;
top: 0px;
}
.underPanel:nth-child(even) > .panel {
background-color: #303030;
}
<meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1.0">
<div class="panelsContainer">
<div class="underPanel">Hello
<div id="panel1" class="panel">1</div>
</div>
<div class="underPanel">Hello
<div id="panel2" class="panel">2</div>
</div>
<div class="underPanel">Hello
<div id="panel3" class="panel">3</div>
</div>
<div class="underPanel">Hello
<div id="panel4" class="panel">4</div>
</div>
</div>
For solving your problem, you need to redefine the target variable in for loop using const like this:
const targetPanel = document.getElementById(plbelements[l].id);
And you'd better use const and let instead of var. The entire JavaScript code is as follows:
const plbelements = document.getElementsByClassName("panel");
for (let l = 0; l < plbelements.length; l++) {
const targetPanel = document.getElementById(plbelements[l].id);
const actionSwipeAmount = "160px";
console.log("Target Panel before event listener = " + targetPanel.id);
targetPanel.addEventListener("click", (e) => {
left = window.getComputedStyle(targetPanel).getPropertyValue("left");
console.log(targetPanel.id);
if (left != actionSwipeAmount) {
targetPanel.style.left = actionSwipeAmount;
} else {
targetPanel.style.left = "0px";
}
});
}
I cant get the "if" part to work, thus not outputting the text Test0 or Test1 to my "Test" div after I press either of the links. I have checked for any error messages, which there are none of. I also added the changing color to check if it was the event listeners that were the problem, but that worked fine. So my only problem is that I can't get the text to output.
var testEl = document.querySelector("#test");
var menyEl = document.querySelectorAll("a");
for (var i = 0; i < menyEl.length; i++) {
menyEl[i].addEventListener("click", byttInfo);
}
function byttInfo(e) {
if (e.target.className === "ikke_aktiv") {
for (var i = 0; i < menyEl.length; i++) {
menyEl[i].className = "ikke_aktiv";
}
e.target.className = "aktiv"
}
if (e.target.value === 0) {
testEl.innerHTML = "Test0"
} else if (e.target.value === 1) {
testEl.innerHTML = "Test1"
}
}
.innpakning {
width: 80%;
background-color: #708790;
padding: 10px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.loddrett_meny {
display: flex, block;
flex: 1;
padding-top: 6px;
}
.loddrett_meny a {
display: block;
text-align: center;
padding: 12px;
margin: 4px;
color: white;
font-size: 20px;
text-decoration: none;
}
.loddrett_meny a:hover {
background-color: black;
border-radius: 8px;
transition: 0.75s;
}
.aktiv {
background-color: #3cb500;
}
.ikke_aktiv {
background-color: #555;
}
.innhold,
#test {
flex: 6;
height: auto;
background-color: #a6d4a3;
padding-left: 2px;
border-radius: 2px;
margin: 10px;
margin-right: 0px;
font-size: 20px;
}
<div class="innpakning">
<div class="loddrett_meny">
<a class="aktiv" value="0">Kapittel 20</a>
<a class="ikke_aktiv" value="1">Kapittel 20.1</a>
</div>
<div id="test"></div>
</div>
You need to use quotes around values or convert them to Number
if(e.target.value === "0"){
testEl.innerHTML = "Test0"
}else if(Number(e.target.value) === 1){
testEl.innerHTML = "Test1"
}
Adding on what Abdulah Proho said: You can't add the value attribute to a tags, so it's discarded and e.target.value. You may use data attributes for this:
var testEl = document.querySelector("#test");
var menyEl = document.querySelectorAll("a");
for (var i = 0; i < menyEl.length; i++) {
menyEl[i].addEventListener("click", byttInfo);
}
function byttInfo(e) {
if (e.target.className === "ikke_aktiv") {
for (var i = 0; i < menyEl.length; i++) {
menyEl[i].className = "ikke_aktiv";
}
e.target.className = "aktiv"
}
if (e.target.dataset.value === "0") {
testEl.innerHTML = "Test0"
} else if (e.target.dataset.value === "1") {
testEl.innerHTML = "Test1"
}
}
.innpakning {
width: 80%;
background-color: #708790;
padding: 10px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.loddrett_meny {
display: flex, block;
flex: 1;
padding-top: 6px;
}
.loddrett_meny a {
display: block;
text-align: center;
padding: 12px;
margin: 4px;
color: white;
font-size: 20px;
text-decoration: none;
}
.loddrett_meny a:hover {
background-color: black;
border-radius: 8px;
transition: 0.75s;
}
.aktiv {
background-color: #3cb500;
}
.ikke_aktiv {
background-color: #555;
}
.innhold,
#test {
flex: 6;
height: auto;
background-color: #a6d4a3;
padding-left: 2px;
border-radius: 2px;
margin: 10px;
margin-right: 0px;
font-size: 20px;
}
<div class="innpakning">
<div class="loddrett_meny">
<a class="aktiv" data-value="0">Kapittel 20</a>
<a class="ikke_aktiv" data-value="1">Kapittel 20.1</a>
</div>
<div id="test"></div>
</div>
e.target.value is undefined. Due to anchor tags usually not having value attribute. The 'a' elements don't have the data prototype for value.
You should try getting the value using:
e.target.getAttribute('value')
Also while comparing try using:
e.target.getAttribute('value') === '0'
Given the value you get from getAttribute function is a string the value getting compared with should also be a string.
The following works I have tested it as a snippet. Trying copying this entirely and replace it with your js. you need to use the getAttribute method to get the value.
var testEl = document.getElementById("test");;
var menyEl = document.querySelectorAll("a");
for (var i = 0; i < menyEl.length; i++) {
menyEl[i].addEventListener("click", byttInfo);
}
function byttInfo(e) {
if (e.target.className === "ikke_aktiv") {
for (var i = 0; i < menyEl.length; i++) {
menyEl[i].className = "ikke_aktiv";
}
e.target.className = "aktiv"
}
if (e.target.getAttribute("value") === "0"){
testEl.innerText = "Test0"
} else if (e.target.getAttribute("value") === "1") {
testEl.innerText = "Test1"
}
}
i want to no repeat the tags that i will writing in field i try but the console appears the span value repeat like this in image how can i fix that to not repeat the tags. i used JQuery
s://i.stack.imgur.com/dIVP1.jpg
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<input class="add-tags" type="text" placeholder="Type Your Tags">
<div class="tags"></div>
</div>
<script>
$('.add-tags').on('keyup', function(e) {
var tagsKey = e.keyCode || e.which;
if (tagsKey === 188) {
var thisValue = $(this).val().slice(0, -1); //remove last letter
$('.tags').append('<span class="tags-span"><i class="fa fa-times"></i>' + thisValue + '</span>');
var spanvalue = $('.tags-span').text();
console.log(spanvalue);
if (thisValue === spanvalue) {
console.log('good');
} else {
console.log('bad');
}
$(this).val('');
}
$('.tags').on('click', '.tags-span i', function() {
$(this).parent('.tags-span').remove();
});
});
</script>
Voila!
I have a gift for you, but first I would like to point out, that next time you should invest more time into the preparation of your question. Don't cry, don't beg, start from doing your homework first and get as much information as you can. Stackoverflow is not a place were people will do you job for you.
Right now, one can only guess what you are really trying to achieve.
After some harsh treatment let's go to the good parts:
In the following example (https://jsfiddle.net/mkbctrlll/xb6ar2n1/95/)
I have made a simple input that creates a tag on a SPACE key hit. Each tag could be easily removable if X is clicked.
HTML:
<form class="wrapper">
<label for="test">
<span id="tags">
Tags:
</span>
<input id="test" type="text" >
</label>
</form>
JS:
var tagsCollection = []
document.body.onkeyup = function(e){
if(e.keyCode == 32){
var content = getContent('#test')
console.log(tagsCollection.indexOf(content))
if(tagsCollection.indexOf(content) === -1) {
console.log('Spacebar hit! Creating tag')
createTag(content)
tagsCollection.push(content)
console.log(tagsCollection)
} else {
console.log('We already have this one sir!')
displayError('Whoops! Looks like this tag already exists... )')
}
}
}
$('.wrapper').on('click', function(event) {
$(event.target).closest('.tag').remove()
})
function displayError(content) {
var error = document.createElement('p')
error.classList.add('error')
error.innerHTML = content
document.querySelector('.wrapper').append(error)
}
function getContent(target) {
var value = $(target).val().replace(/\W/g, '')
$(target).val("")
return value
}
function createTag(content) {
var $tags = $('#tags')
var tag = document.createElement('span')
var closeIcon = '×'
var iconHTML = document.createElement('span')
iconHTML.classList.add('remove')
iconHTML.innerHTML = closeIcon
tag.classList.add('tag')
tag.append(iconHTML)
tag.append(content)
$tags.append(tag)
}
function removeTag(target) {
target.remove()
}
CSS:
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
.wrapper {
background: #fff;
border-radius: 4px;
padding: 20px;
font-size: 25px;
transition: all 0.2s;
margin: 0 auto;
width: 300px;
}
#tags {
display: block;
margin-bottom: 10px;
font-size: 14px;
}
#test {
display: block;
width: 100%;
}
.tag {
border-radius: 16px;
background-color: #ccc;
color: white;
font-size: 12px;
padding: 4px 6px 4px 16px;
position: relative;
}
.tag:not(:last-child) {
margin-right: 4px;
}
.remove {
font-weight: 600;
position: absolute;
top: 50%;
left: 6px;
cursor: pointer;
transform: translateY(-50%);
}
.remove:hover {
color: red;
}
It is just a quick and dirty example, not a production lvl code.
So I am working on creating a custom alert box. I've got most of the code the way I want it.
What I Want:
What I would like is to click the minus to fade the alert box so you can view the html behind it.
What is Wrong:
My issue is the min.onclick code does not click (clicking the minus sign does nothing).
See Below:
var b = document.getElementById('button-container');
var bg = document.createElement('div');
bg.setAttribute('id', 'alert-box');
bg.setAttribute('class','alert');
b.appendChild(bg);
var box = document.createElement('div');
box.setAttribute('id', 'alert-text');
box.setAttribute('class','alert-content');
box.setAttribute('display', 'block');
box.innerHTML = 'Fancy stuff happens here!<br>Look chess pieces';
bg.appendChild(box);
var min = document.createElement('span');
min.setAttribute('id','alert-min');
min.setAttribute('class','alert-min');
min.innerHTML = '−';
var s = true;
min.onclick = function() {
console.log('pressed!');
if(s) {
box.style.opacity = '.25';
s = false;
}
else{
box.style.opacity = '1';
s = true;
}
};
box.appendChild(min);
box.innerHTML += '<br><br>';
var images = ['q', 'n', 'r', 'b'];
var t = ['1/15', '7/70', '7/72', 'b/b1'];
for(var i = 0; i < images.length; i++) (function(i){
var btn = document.createElement('button');
btn.setAttribute('class','alert-button');
btn.setAttribute('id',images[i]+'btn');
btn.onclick = function () {
console.log('You clicked: ', images[i]);
};
box.appendChild(btn);
var img = document.createElement('img');
img.setAttribute('id',images[i]+'img');
img.setAttribute('src','https://upload.wikimedia.org/wikipedia/commons/thumb/'+t[i]+'/Chess_'+images[i]+'lt45.svg/45px-Chess_'+images[i]+'lt45.svg.png');
img.setAttribute('class','alert-image');
btn.appendChild(img);
})(i);
.alert {
display: block;
position: fixed;
z-index: 1;
padding-top: 10px;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.4);
}
.alert-content {
background-color: #daac27;
margin: auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
}
.alert-min {
color: #fff;
float: right;
font-size: 28px;
font-weight: bold;
}
.alert-min:hover,
.alert-min:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
<br><br><br>
O no! You can't see me!
<div id="button-container">
</div>
To be honest I have no idea why your script does not work. I did nothing but appending the close "button" after that loop. Now the click handler is working.
edit:
i also edited the other console.log due to it printed undefined
var b = document.getElementById('button-container');
var bg = document.createElement('div');
bg.setAttribute('id', 'alert-box');
bg.setAttribute('class','alert');
b.appendChild(bg);
var box = document.createElement('div');
box.setAttribute('id', 'alert-text');
box.setAttribute('class','alert-content');
box.setAttribute('display', 'block');
box.innerHTML = 'Fancy stuff happens here!<br>Look chess pieces';
bg.appendChild(box);
box.innerHTML += '<br><br>';
var images = ['q', 'n', 'r', 'b'];
var t = ['1/15', '7/70', '7/72', 'b/b1'];
for(var i = 0; i < images.length; i++) {
var btn = document.createElement('button');
btn.setAttribute('class','alert-button');
btn.setAttribute('id',images[i]+'btn');
let tmp = images[i]
btn.onclick = function () {
console.log('You clicked: ', tmp);
};
box.appendChild(btn);
var img = document.createElement('img');
img.setAttribute('id',images[i]+'img');
img.setAttribute('src','https://upload.wikimedia.org/wikipedia/commons/thumb/'+t[i]+'/Chess_'+images[i]+'lt45.svg/45px-Chess_'+images[i]+'lt45.svg.png');
img.setAttribute('class','alert-image');
btn.appendChild(img);
}
var min = document.createElement('span');
min.setAttribute('id','alert-min');
min.setAttribute('class','alert-min');
min.innerHTML = '−';
var s = true;
min.onclick = function() {
console.log('pressed!');
if(s) {
box.style.opacity = '.25';
s = false;
}
else{
box.style.opacity = '1';
s = true;
}
};
box.appendChild(min);
.alert {
display: block;
position: fixed;
z-index: 1;
padding-top: 10px;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.4);
}
.alert-content {
background-color: #daac27;
margin: auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
}
.alert-min {
color: #fff;
float: right;
font-size: 28px;
font-weight: bold;
}
.alert-min:hover,
.alert-min:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
<br><br><br>
O no! You can't see me!
<div id="button-container">
</div>
I've got some kind of drop down menu dynamically appending to differents divs. Problem is, when someone click on "close", then style.display = "none" wont work. I can change background, opacity, size but i cant hide it.
Code looks like this:
<style>
html, body{
height: 98%;
}
#editorViewport{
width: 90%;
height: 100%;
min-width: 400px;
min-height: 300px;
position: relative;
margin: 0 auto;
border: 1px solid red;
}
#movingElementsContainer{
display: none;
top: 0px;
left: 0px;
}
#addStartingElementBtn{
width: 60px;
height: 60px;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
}
#addStartingElementBtn:hover{
background-color: #c9eac6;
border: 1px solid grey;
cursor: pointer;
}
#elementsMenuContainer{
width: 150px;
border: 1px solid grey;
background-color: white;
min-height: 100px;
padding: 5px;
position: absolute;
z-index: 2;
display: none;
}
.elementOption{
width: 90%;
padding: 5px;
border: 1px solid grey;
}
.elementOption:hover{
border: 1px solid red;
cursor: pointer;
}
</style>
<body>
<div id="editorViewport">
<div id="addStartingElementBtn" data-Owner="starting" data-Side="starting" class="openElementsMenu">
Click!
</div>
</div>
<div id="movingElementsContainer">
<div id="elementsMenuContainer" data-Open="false" data-Owner="" data-Side="">
<div data-Kind="1" class="elementOption">
One
</div>
<div data-Kind="2" class="elementOption">
Two
</div>
<div data-Kind="3" class="elementOption">
Three
</div>
<div data-Kind="99" class="elementOption">
Close
</div>
</div>
</div>
</body>
<script type="text/javascript">
function prepareEventHandlers(){
var openElementsMenu = document.getElementsByClassName("openElementsMenu");
var event = window.attachEvent ? 'onclick' : 'click';
for(var i = 0; i < openElementsMenu.length; i++){
if(openElementsMenu[i].addEventListener){
openElementsMenu[i].addEventListener('click', elementsMenu, false);
}else{
openElementsMenu[i].attachEvent('onclick', elementsMenu);
}
}
var elementOption = document.getElementsByClassName("elementOption");
for(var i = 0; i < elementOption.length; i++){
if(elementOption[i].addEventListener){
elementOption[i].addEventListener('click', selectElementToCreate, false);
}else{
elementOption[i].attachEvent('onclick', selectElementToCreate);
}
}
}
window.onload = function(){
prepareEventHandlers();
}
var totalElements = 0;
var editorViewport = "editorViewport";
var selectedElementId = "";
var elementsMenu = function(){
var elementsMenu = document.getElementById("elementsMenuContainer")
this.appendChild(elementsMenu);
elementsMenu.style.display = "block";
elementsMenu.style.left = 61 + "px";
elementsMenu.style.top = "0px";
elementsMenu.setAttribute("data-Open", "true");
elementsMenu.setAttribute("data-Owner", this.getAttribute("data-Owner"));
elementsMenu.setAttribute("data-Side", this.getAttribute("data-Side"));
}
var selectElementToCreate = function(){
var dataKind = this.getAttribute('data-Kind');
var parentNode = document.getElementById(this.parentNode.id);
alert(dataKind)
if(dataKind == "99"){
parentNode.style.display = "none"
parentNode.setAttribute("data-Open", "false");
parentNode.setAttribute("data-Owner", "");
parentNode.setAttribute("data-Side", "");
}
}
</script>
Here is a JSFiddle
Many thanks for any advise!
var selectElementToCreate = function(e){
var dataKind = this.getAttribute('data-Kind');
var parentNode = document.getElementById(this.parentNode.id);
alert(dataKind)
if(dataKind == "99"){
console.log(parentNode);
parentNode.style.display = "none"
parentNode.setAttribute("data-Open", "false");
parentNode.setAttribute("data-Owner", "");
parentNode.setAttribute("data-Side", "");
alert("Wont Close :");
}
e.stopPropagation();
}
You are moving the element into the clicked element.
var elementsMenu = document.getElementById("elementsMenuContainer")
this.appendChild(elementsMenu);
At first the menu item's click handler is executed which sets the display property to none and as the click event bubbles then the event handler of the wrapper element is executed and sets the display property to block.
You should stop the propagation of the event using stopPropagation method of the event object.
var selectElementToCreate = function (event) {
event.stopPropagation();
var dataKind = this.getAttribute('data-Kind');
var parentNode = this.parentNode;
if (dataKind == "99") {
parentNode.style.display = "none";
// ...
}
}