I made a script that when I click on the container it hides a list. However, what I have been trying to do is that the list should hide when clicking outside the container and not inside. I have been looking for answers but nothing really worked for me as I use classes. Does someone know a solution?
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width" />
<title>Hiding the list</title>
</head>
<body>
<h1>Hiding the list</h1>
<div class="list">Hide the list by clicking outside
<li>Text1</li>
<li>Text2</li>
<li>Text3</li>
</div>
<div class="list">Hide the list by clicking outside
<li>Text1</li>
<li>Text2</li>
<li>Text3</li>
</div>
</body>
</html>
<style>
.list {
width: 50%;
height: 100%;
background-color: #f2f2f2;
}
li {
}
</style>
<script>
function hide_list() {
var children = this.children;
for (let i = 0; i < children.length; i++) {
children[i].style.display = "none";
}
}
document.querySelectorAll(".list").forEach(function (elem) {
elem.addEventListener("click", hide_list);
});
</script>
Related
I'm trying to create an online commenting system where each user can comment on a post and I want a popup text area to be unique to its own button.
Each element is meant to open a text field where a user is to input text to be posted (say in reply to a preceding post or comment).
There are three buttons (representing each user) which when clicked is intended to display a text field specific to the button (or user).
The problem:
After clicking a button, a modal will popup, try typing some text into the field and close the field, without clearing the text in the field, then open another field by clicking on another button. You'll notice that the text typed into one textarea will also be visible in another instance when you click on another button.
What I'm trying to achieve is to make a textarea unique to its direct button instead of a text constantly showing for all buttons clicked.
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./style.css" />
<title>multi textarea</title>
</head>
<body>
<button>Open a textarea</button>
<button>Open a textarea</button>
<button>Open a textarea</button>
<div class="textarea_modal_backdrop">
<textarea name="" id="" cols="80" rows="20"></textarea>
</div>
</body>
</html>
<script src="./script.js"></script>
CSS:
.textarea_modal_backdrop{
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: #444c;
display: grid;
place-items: center;
visibility: hidden;
opacity: 0;
}
.textarea_modal_backdrop.textarea_modal_backdrop_active{
visibility: visible;
opacity: 1;
}
JS:
const allButtonElms = document.getElementsByTagName('button');
const modalBackdrop = document.querySelector('.textarea_modal_backdrop');
for (var i = 0; i < allButtonElms.length; i+=1) {
allButtonElms[i].onclick = () => {
modalBackdrop.classList.add('textarea_modal_backdrop_active')
}
}
document.addEventListener('click', (event) => {
if (event.target.matches('.textarea_modal_backdrop')) {
modalBackdrop.classList.remove('textarea_modal_backdrop_active')
}
})
I'll be grateful if everyone can join in sharing their ideas on how this issue can be solved.
Thank you all!
one way can be to
stored textarea values in an array of value
add a dataset on button to identify value link to textarea
when textarea is closed save data in values array
const values = [];
var currentButton = 0;
const allButtonElms = document.getElementsByTagName('button');
const modalBackdrop = document.querySelector('.textarea_modal_backdrop');
const textarea = document.querySelector('textarea');
for (var i = 0; i < allButtonElms.length; i+=1) {
allButtonElms[i].onclick = (e) => {
var target = e.target || e.srcElement;
currentButton = target.dataset.number;
if (!values[currentButton]) {
values[currentButton] = "";
}
textarea.value = values[currentButton];
modalBackdrop.classList.add('textarea_modal_backdrop_active')
}
}
document.addEventListener('click', (event) => {
if (event.target.matches('.textarea_modal_backdrop')) {
values[currentButton] = textarea.value;
modalBackdrop.classList.remove('textarea_modal_backdrop_active')
}
})
.textarea_modal_backdrop{
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: #444c;
display: grid;
place-items: center;
visibility: hidden;
opacity: 0;
}
.textarea_modal_backdrop.textarea_modal_backdrop_active{
visibility: visible;
opacity: 1;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./style.css" />
<title>multi textarea</title>
</head>
<body>
<button data-number="0">Open a textarea</button>
<button data-number="1">Open a textarea</button>
<button data-number="2">Open a textarea</button>
<div class="textarea_modal_backdrop">
<textarea name="" id="" cols="80" rows="20"></textarea>
</div>
</body>
</html>
<script src="./script.js"></script>
<style>
#first
{
width:100%;
height:1000px;
background:red;
}
#second
{
width:100%;
height:1000px;
background:blue;
}
</style>
<body>
<div id="first">
</div>
<div id="second">
<h1 id="welcome">Welcome</h1>
</div>
</body>
What I want to achieve here is that on scrolling down the document I wanted the "h1 tag to fade in and appear as soon as I reach id="second". How to do that with JS. I have tried a couple of things, but nothing is working out the way I want. I also browsed regarding animation on scrolling and got results but I m not getting what's happening really. Can someone plz help me out in this? I m completely new to JS and trying out various kinds of stuff.
Thank you.
If you want to use the fade-in for multiple elements. Give a class to these elements and use the loop which is already commented.
$(document).ready(function() {
$(window).scroll( function(){
// $('.fadein').each( function(i){
var bottom_of_element = $('#welcome').offset().top + $('#welcome').outerHeight();
var bottom_of_window = $(window).scrollTop() + $(window).height();
if( bottom_of_window > bottom_of_element ){
$('#welcome').animate({'opacity':'1'},1000);
}
// });
});
});
div {
height: 600px
}
#first {
background: red;
}
#second {
background: green;
}
#welcome {
opacity: 0;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>h1 fade-in</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<div id="first">
</div>
<div id="second">
<h1 id="welcome">Welcome</h1>
</div>
</body>
</html>
I need to build a window listener that triggers on the mouseover on a box using contains and I'm not quite sure of how to build that?
This is a test I've built:
window.addEventListener("mouseover", trial)
function trial(e) {
const contain_material = document.getElementsByClassName("item")
if(contain_material.contains(e.target)) {
alert("so far so good")
}
else {
return
}
}
See if the following works for you.
function trial(e) {
const contain_material = document.getElementsByClassName("item")
for (var i = 0; i < contain_material.length; i++) {
if(contain_material[i] == e.target) {
alert("so far so good")
}
}
}
Instead of checking hover on the window, why not just check when one of those elements is hovered over. For example:
const contain_material = document.getElementsByClassName("item")
for (mat of contain_material) {
mat.addEventListener("mouseover", trial)
}
function trial(e) {
alert("so far so good")
}
Can't you just listen to the mouseover on the box element instead of in the whole page?
function handleMouseOver() {
alert('so far so good')
}
// or you can add dynamicaly with js
var boxes = document.getElementsByClassName("item");
Array.from(boxes).forEach(function() {
this.onmouseover = () => alert('so far so good')
})
// () => this is an arrow function in case you dont know
// Array.from() is because you can't use the forEach straight with a HTMLCollection
body {
display: flex;
}
.item {
width: 300px;
height: 300px;
background-color: yellow;
margin: 10px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div class="item" onmouseover="handleMouseOver()"></div>
<div class="item" onmouseover="handleMouseOver()"></div>
<div class="item" onmouseover="handleMouseOver()"></div>
<div class="item" onmouseover="handleMouseOver()"></div>
</body>
</html>
ul.cars(data-ng-show="$ctrl.hasCars")
li.skill("data-ng-repeat="car in $ctrl.cars")
How can I make my window automatically scroll to the last li when is added each time?
As mentioned in the comment you could use Element.scrollIntoView(), you could use :last-child selector to select the last li.
Here is an example of this in action.
var list = document.querySelector('.list');
var button = document.querySelector('.updateList');
function updateList(){
var number = Math.round(Math.random()*100);
var li = document.createElement('li');
li.textContent = number;
list.appendChild(li);
var lastLi = document.querySelector('.list li:last-child');
lastLi.scrollIntoView();
}
button.addEventListener('click', updateList);
.app{
width: 100vw;
height: 100vh;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<button class="updateList">Update List</button>
<div class="app"></div>
<ul class="list">
<li>hello</li>
<li>World</li>
<li>Whats up</li>
</ul>
</body>
</html>
Here is a jsbin of the above code https://jsbin.com/beqovi/edit?html,css,output
I'm practicing basic JS skills by setting up little exercises for myself. In this one, I have a list of <a>s inside a div. The aim of the exercise is to wrap each <a> in a div. I'm using replaceChild in this instance.
Oddly (to me at least) the script works for the first three links, but after that throws an error:
Uncaught TypeError: Cannot read property 'parentNode' of undefined
I can't tell why the script partly works. Can anyone see what I'm doing wrong here? Here's the code I'm using:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style media="all">
div div {padding: 10px; background: #e7e7e7; margin: 5px;}
</style>
</head>
<body>
<div>
link
link
link
link
link
link
</div>
<script>
var links = document.getElementsByTagName("a");
for (var i=0, ii=links.length; i<ii; i++)
{
var container = document.createElement("div");
links[i].parentNode.replaceChild(container, links[i]);
container.appendChild(links[i]);
}
</script>
</body>
</html>
and here's an online version: http://codepen.io/anon/pen/Lpuky
I've tried the few debugging techniques that I know of and read about this error message, but haven't worked out what's wrong here. Seems funny to me that it works for 3 of the 6 links.
The collection links is NodeList and is live.
Since you are replacing them, they are disappearing from the collection and our index into them is no longer pointing to anything.
You're modifying the nodelist as you iterate over it. Use the Array slice method to make a copy of the list:
var linksCopy = Array.prototype.slice.call(links);
for (var i=0; i<linksCopy.length; i++)
{
var container = document.createElement("div");
linksCopy[i].parentNode.replaceChild(container, linksCopy[i]);
container.appendChild(linksCopy[i]);
}
Regarding your own follow-up answer: if your objective was simply to find the easiest way to wrap the <a>s in <div>s, rather than to practice with createElement, replaceChild or appendChild or any of the other methods, this would be it:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Demo</title>
<style>
div div {
padding: 10px;
background: #e7e7e7;
margin: 5px;
}
</style>
</head>
<body>
<div>
link
link
link
link
link
link
</div>
<script>
var links = document.querySelectorAll("a");
for (var i=0; i<links.length; i++) {
links[i].outerHTML = '<div>'+links[i].outerHTML+'</div>';
}
</script>
</body>
</html>
.
Live demo here: http://jsbin.com/jasoho/1/edit?html,output. Another advantage of the outerHTML method is that it doesn't change the nodeList. So you can also use getElementsByTagName in stead of querySelectorAll.
As a follow up to this, I often hear that querySelectorAll() is different in that it returns a static Nodelist rather than an array, so I thought that might come in handy here, and indeed it does:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style media="all">
div div {padding: 10px; background: #e7e7e7; margin: 5px;}
</style>
</head>
<body>
<div>
link
link
link
link
link
link
</div>
<script>
var links = document.querySelectorAll("a");
for (var i=0, ii=links.length; i<ii; i++)
{
var container = document.createElement("div");
links[i].parentNode.replaceChild(container, links[i]);
container.appendChild(links[i]);
}
</script>
</body>
</html>
Also, an alternative to Array.prototype.slice.call(links) is [].slice.call(links):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style media="all">
div div {padding: 10px; background: #e7e7e7; margin: 5px;}
</style>
</head>
<body>
<div>
link
link
link
link
link
link
</div>
<script>
var links = document.getElementsByTagName("a");
var linksCopy = [].slice.call(links);
for (var i=0; i<linksCopy.length; i++)
{
var container = document.createElement("div");
linksCopy[i].parentNode.replaceChild(container, linksCopy[i]);
container.appendChild(linksCopy[i]);
}
</script>
</body>
</html>
And another option again is to use [].forEach.call():
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style media="all">
div div {padding: 10px; background: #e7e7e7; margin: 5px;}
</style>
</head>
<body>
<div>
link
link
link
link
link
link
</div>
<script>
[].forEach.call(document.querySelectorAll('a'), function(el) {
var container = document.createElement("div");
el.parentNode.replaceChild(container, el);
container.appendChild(el);
});
</script>
</body>
</html>
Yet another option, using Array.from():
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style media="all">
div div {padding: 10px; background: #e7e7e7; margin: 5px;}
</style>
</head>
<body>
<div>
link
link
link
link
link
link
</div>
<script>
var links = document.getElementsByTagName("a");
var linksCopy = Array.from(links);
for (var i=0; i<linksCopy.length; i++)
{
var container = document.createElement("div");
linksCopy[i].parentNode.replaceChild(container, linksCopy[i]);
container.appendChild(linksCopy[i]);
}
</script>
</body>
</html>