Frank
Frank

Reputation: 23

Which is the correct way to add an event to all elements?

I tried this but it doesn't work. Each text element should change the corresponding image. In the browser console city_name appears as html collections

let city_name = document.getElementsByClassName("city_name");
let city_img = document.getElementsByClassName("city_img");


for (let i = 0; i < city_name.length; i++) {
    city_name[i].addEventListener("mouseover", blur(i))   
}
    
function blur(i) {
    city_img[i].style.filter = "blur(4px)"  
}
<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="style.css">
    <script src="API.js"></script>
    <title>WeatherLike</title>

</head>

<body>
    <div class="top_city">

        <div class="city">
            <img src="milano.jpg" class="city_img">
            <h1 class="city_name">Milano</h1>
        </div>
        <div class="city">
            <img src="torino.jpg" class="city_img">
            <h1 class="city_name">Torino</h1>
        </div>
        <div class="city">
            <img src="bologna.jpg" class="city_img">
            <h1 class="city_name">Bologna</h1>
        </div>
        <div class="city">
            <img src="firenze.jpg" class="city_img">
            <h1 class="city_name">Firenze</h1>
        </div>
        <div class="city">
            <img src="roma.jpg" class="city_img">
            <h1 class="city_name">Roma</h1>
        </div>
        <div class="city">
            <img src="napoli.jpg" class="city_img">
            <h1 class="city_name">Napoli</h1>
        </div>
        <div class="city">
            <img src="palermo.jpg" class="city_img">
            <h1 class="city_name">Palermo</h1>
        </div>
   
        
    </div>  
</body>

</html>

Thanks.

@ChrisG @Adyson yes, ChrisG is right. But "hover the name and the image gets blurry" doesn't work in my HTML page. Maybe for the CSS?

@import url('https://fonts.googleapis.com/css2?family=Bitter:wght@700&display=swap');

*{
    margin: 0;
    padding: 0;
}

body{
    height: 100vh;
}

.top_city{
    display: flex;
    flex-direction: row;
    height: 20vh;
    
}

.city_img{
    background-size: cover;
    border: 1px solid lightgrey;
    height: 20vh;   
}

.city_name{
    color: white;
    text-align: center;
    position: absolute;
    width: 14.2%;
    margin-top: 55px;
    font-family: 'Bitter', serif ;
    border: 1px solid rgb(255, 255, 255);
    text-shadow: 1px 1px 1px black;
    background-color: rgb(0,0,0); /* Fallback color */
    background-color: rgba(0,0,0, 0.2); /* Black w/opacity/see-through */
}

.city{
    overflow: hidden;
    display: flex;
    width: 16.66%;
}

Upvotes: 1

Views: 101

Answers (5)

ilbert
ilbert

Reputation: 53

I assume your js script is in the API.js file, that you have imported in the <head> section of your HTML file. The problem is that the script is imported and executed during the loading of the page, so it can't see the HTML elements (called by document.getElementsByClassName function) yet.

You can fix it in many ways:

  1. Import your API.js script after the HTML elements you need to call:

    <div class="top_city">
    
        <div class="city">
            <img src="milano.jpg" class="city_img">
            <h1 class="city_name">Milano</h1>
        </div>
        ...
    
    </div>
    
    <script src="API.js"></script>
    
    <!-- other code here -->
    
    </body>
    
  2. Add the async tag:

    <script src="API.js" async></script>
    
  3. Execute your code during the loading of the page. I think this the best practice:

    window.onload = function(){
        let city_name = document.querySelectorAll(".city_name");
        let city_img = document.querySelectorAll(".city_img");
    
        for (let i = 0; i < city_name.length; i++) {
            city_name[i].addEventListener("mouseover", (e)=>{blur(e)})   
        }
    
        function blur(e) {
            e.target.previousElementSibling.style.filter = "blur(4px)"  
        }
     }
    

    See this answer for more details.

Upvotes: 0

Gazowski
Gazowski

Reputation: 66

If you place the name (<h1> tags) before the image (<img>), you can reach your event listener only with css and you don't need any javascript code :

h1:hover + img{
  filter:blur(4px);
}

Upvotes: 0

Gazowski
Gazowski

Reputation: 66

You have several problems in your code :

  1. getElementsByClass return a collection and not an array as you expected. You should use document.querySelectorAll to get an array of your elements.
  2. As it has already said , you need a callback for your function blur
  3. instead of passing i in parameters, you're better to use the event.target to be sure to blur the right element. use previousElementSibling to spot the picture.
    let city_name = document.querySelectorAll(".city_name");
    let city_img = document.querySelectorAll(".city_img");

    for (let i = 0; i < city_name.length; i++) {
        city_name[i].addEventListener("mouseover", (e)=>{blur(e)})   
    }

    function blur(e) {
        e.target.previousElementSibling.style.filter = "blur(4px)"  
    }

Upvotes: 2

Benoit
Benoit

Reputation: 1107

You need to create a function callback, because now it assume the blur function return a function callback.

Replace the blur(i) with function(){ blur(i); }

let city_name = document.getElementsByClassName("city_name");
let city_img = document.getElementsByClassName("city_img");


for (let i = 0; i < city_name.length; i++) {
    city_name[i].addEventListener("mouseover", function(){ blur(i); });   
}
    
function blur(i) {
    city_img[i].style.filter = "blur(4px)";
}
<!DOCTYPE html>
<html lang="en">
<head>
    
    <title>WeatherLike</title>

</head>

<body>
    <div class="top_city">

        <div class="city">
            <img style="height:45px;" src="https://s3.amazonaws.com/pix.iemoji.com/images/emoji/apple/ios-12/256/united-states.png" class="city_img">
            <h1 class="city_name">Milano</h1>
        </div>
        <div class="city">
            <img style="height:45px;" src="https://s3.amazonaws.com/pix.iemoji.com/images/emoji/apple/ios-12/256/uruguay.png" class="city_img">
            <h1 class="city_name">Torino</h1>
        </div>
        <div class="city">
            <img src="bologna.jpg" class="city_img">
            <h1 class="city_name">Bologna</h1>
        </div>
        <div class="city">
            <img src="firenze.jpg" class="city_img">
            <h1 class="city_name">Firenze</h1>
        </div>
        <div class="city">
            <img src="roma.jpg" class="city_img">
            <h1 class="city_name">Roma</h1>
        </div>
        <div class="city">
            <img src="napoli.jpg" class="city_img">
            <h1 class="city_name">Napoli</h1>
        </div>
        <div class="city">
            <img src="palermo.jpg" class="city_img">
            <h1 class="city_name">Palermo</h1>
        </div>
   
        
    </div>  
</body>

</html>

Upvotes: 1

Rick
Rick

Reputation: 1870

you likely need an 'id' tag on each image and then reference it in your blur() function.

by the way have you considered using a more structured framework like angular? this entire page could be written like this:

<div class="city" *ngFor="let city of cityList">
  <img id="{{city.id}}" src="{{city.img}}" class="city_img">
  <h1 class="city_name" (blur)="blurCity(city)">{{city.name}}</h1>
</div>

Upvotes: -2

Related Questions