i want to achieve this behaviour from this example with images https://codepen.io/ryanfinni/pen/jONBEdX. the only difference it's that instead on toggling the img visibility, for every div that it's in view, i want to make an call to an endpoint to retrieve the data and ppulate the html by sendind the corresponding data-id as a parameter.
what i have so far it's working only for the first item. how can i make it work for all the items that i have and target them by the data-id, similar to this example with data.src
function handleIntersection(entries) {
entries.map((entry) => {
if (entry.isIntersecting) {
entry.target.src = entry.target.dataset.src;
entry.target.classList.add('loaded')
observer.unobserve(entry.target);
}
});
}
here is my code
const LIST = document.querySelector('.city-list');
async function getData() {
try {
let response = await fetch('https://raw.githubusercontent.com/ashes27/infinite/master/ids.json');
if (response.status == 200) {
let data = await response.json();
return data;
} else {
throw new Error(response.status);
}
} catch (error) {
console.log(error);
}
}
getData().then((data) => {
for (const details in data.data.items) {
const LI = document.createElement('li');
const TITLE = document.createElement('h2');
TITLE.className = 'city-title';
TITLE.innerText = data.data.items[details].title;
LI.appendChild(TITLE);
LIST.appendChild(LI);
for (const id in data.data.items[details].ids) {
const DIV = document.createElement('div');
DIV.setAttribute('data-id', data.data.items[details].ids[id]);
DIV.className = 'wrapper';
const markup = `
<div class="city-wrapper" >
<div class="result-wrapper">
<div class="image-wrapper">
<img src=""/>
</div>
<div class="content-wrapper">
<div class="content-info">
<div class="info-wrapper">
<h2></h2>
<span class="address"></span>
</div>
</div>
<p class="description"></p>
</div>
</div>
</div>
</div>
`;
DIV.innerHTML = markup;
LI.appendChild(DIV);
}
}
});
var observer = new IntersectionObserver(
function (entries) {
if (entries[0].isIntersecting === true) {
observer.unobserve(document.querySelector('.city-list'));
const getInfo = async function (post) {
let infoResponse = await fetch('https://raw.githubusercontent.com/ashes27/infinite/master/single-item.json');
let info = await infoResponse.json();
return info;
};
getInfo().then((info) => {
console.log(info);
let itemsInfo = info.data.items;
const DIV = LIST.querySelector('.wrapper');
console.log(DIV);
const markup = `
<div class="city-wrapper" >
<div class="result-wrapper">
<div class="image-wrapper">
<img src="${itemsInfo.mainImgUrl}"/>
</div>
<div class="content-wrapper">
<div class="content-info">
<div class="info-wrapper">
<h2>${itemsInfo.visitTitle}</h2>
<span class="address">${itemsInfo.address}</span>
</div>
</div>
<p class="description">${itemsInfo.mainDescription}</p>
</div>
</div>
</div>
</div>
`;
DIV.innerHTML = markup;
});
}
},
{ threshold: [0] }
);
observer.observe(document.querySelector('.city-list'));
.city-wrapper {
height: 440px;
}
img {
width: 400px;
}
<div style="height: 400px;"></div>
<div style="height: 400px;"></div>
<div style="height: 400px;"></div>
<div style="height: 400px;"></div>
<div style="height: 400px;"></div>
<div style="height: 400px;"></div>
<div style="height: 400px;"></div>
<div style="height: 400px;"></div>
<ul class="city-list">
</ul>
thanks in advance!
You've told your observer to watch for an intersection of .city-list
with the viewport. But you want to know when any of the .wrapper
elements (the ones with the data-id
) in the list gets (or is about to get) visible.
Therefor you have to .observe()
these div.wrapper
elements and not the complete list:
observer.observe(DIV);
To remove an element that has just become visible you have to use the target
property of the current IntersectionObserverEntry
:
observer.unobserve(entries[0].target);
The data-id
you're looking for is also available through the same property:
const dataId = entries[0].target.dataset.id;
As we're going to "observe" multiple elements we have to adjust the logic accordingly:
entries.forEach(entry => {
// ...
});
A complete, but slightly reduced (dummy data, no getInfo()
) example:
const observer = new IntersectionObserver(
function (entries) {
entries.forEach(entry => {
if (entry.isIntersecting === true) {
observer.unobserve(entry.target); // remove the current item from the "watchlist"
console.log(entry.target.dataset.id); // the id you're looking for
}
});
},
{ threshold: [0] }
);
async function getData() {
// dummy data
return Promise.resolve({
data: {
items: {
city1: { title: "City 1", ids: [1, 2, 3] },
city2: { title: "City 2", ids: [4, 5, 6] }
}
}
})
};
getData().then((data) => {
const LIST = document.querySelector('.city-list');
for (const details in data.data.items) {
const LI = document.createElement('li');
const TITLE = document.createElement('h2');
TITLE.className = 'city-title';
TITLE.innerText = data.data.items[details].title;
LI.appendChild(TITLE);
LIST.appendChild(LI);
for (const id in data.data.items[details].ids) {
const DIV = document.createElement('div');
DIV.setAttribute('data-id', data.data.items[details].ids[id]);
DIV.className = 'wrapper';
const markup = `<div class="city-wrapper" >...</div>`;
DIV.innerHTML = data.data.items[details].ids[id] + "<br />" /* so the ID is directly visible */ + markup;
LI.appendChild(DIV);
observer.observe(DIV); // add the current DIV to the "watchlist"
}
}
});
.city-wrapper { height: 440px; }
img { width: 400px; }
<ul class="city-list"></ul>