英文:
Render more containers on scroll ejs not working
问题
I have this frontend code
<div class="bounties">
<% projects.forEach(function(project, index) { %>
<section class="box" style="margin: 1rem;">
<a href="/project/<%=project.UniqueID%>">
<article class="media" style="background: white;">
<div class="media-content">
<div class="content">
<p>
<span style="font-size: 2rem; color: #2d2d2d;margin-left: -2px;">Earn <strong
style="color: #5cb85c">$<%=project.DollarAmount.toLocaleString()%>!</strong></span>
<br>
<span><small><i class="fa-solid fa-clock" style="margin-right: 0.2rem;"></i> Listed <%= getTimePassed(project.ListedDate) %> </small> </span>
<% if(project.Status == 'open') { %>
<div class="status regular tag" style=""><p style="color:black">Open</p></div>
<% } else if(project.Status == 'claimed') { %>
<div class="status claimed tag">Claimed</div>
<% } else if(project.Status == 'closed') { %>
<div class="status closed tag">Closed</div>
<% } else if(project.Status == 'cancelled') { %>
<div class="status closed tag">Cancelled</div>
<% } else if(project.Status == 'completed') { %>
<div class="status claimed tag">Completed</div>
<% } %>
<style>
.status.regular {
font-size: 12px;
height: fit-content;
padding: 6px 10px;
border-radius: 16px;
background-color: lightblue;
font-weight: 400;
opacity: 1;
font-weight: 400;
color:black
}
.tags {
display: flex;
gap: 8px;
}
.tag {
border-radius: 16px;
background-color: #ffc6c2;
font-size: 12px;
color: #690D0D;
background-color: #690D0D;
border: 1px solid transparent;
transition: .4s border-color;
cursor: pointer;
}
.tag:hover {
border-color: #bb7676;
}
.tag,
.status,
.edit,
.delete {
padding: 8px 12px;
display: flex;
align-items: center;
justify-content: center;
}
.status.closed {
font-size: 12px;
height: fit-content;
padding: 6px 10px;
background-color: #FFCCCB;
border-radius: 16px;
}
.status.claimed {
font-size: 12px;
height: fit-content;
padding: 6px 10px;
background-color: lightgreen;
border-radius: 16px;
}
</style>
<h3> <%=project.Title%>
</h3>
</a>
<p> <%=project.Description%> </p>
<a href="/project/<%=project.UniqueID%>">
</div>
<% project.Tags.forEach(function(tag) { %>
<div class="tag"><%= tag %></div>
<% }); %>
<nav class="level is-mobile">
<div class="level
<details>
<summary>英文:</summary>
I have this frontend code
```html
<div class="bounties">
<% projects.forEach(function(project, index) { %>
<section class="box" style="margin: 1rem;">
<a href="/project/<%=project.UniqueID%>">
<article class="media" style="background: white;">
<div class="media-content">
<div class="content">
<p>
<span style="font-size: 2rem; color: #2d2d2d;margin-left: -2px;">Earn <strong
style="color: #5cb85c">$<%=project.DollarAmount.toLocaleString()%>!</strong></span>
<br>
<span><small><i class="fa-solid fa-clock" style="margin-right: 0.2rem;"></i> Listed <%= getTimePassed(project.ListedDate) %> </small> </span>
<% if(project.Status == 'open') { %>
<div class="status regular tag" style=""><p style="color:black">Open</p></div>
<% } else if(project.Status == 'claimed') { %>
<div class="status claimed tag">Claimed</div>
<% } else if(project.Status == 'closed') { %>
<div class="status closed tag">Closed</div>
<% } else if(project.Status == 'cancelled') { %>
<div class="status closed tag">Cancelled</div>
<% } else if(project.Status == 'completed') { %>
<div class="status claimed tag">Completed</div>
<% } %>
<style>
.status.regular {
font-size: 12px;
height: fit-content;
padding: 6px 10px;
border-radius: 16px;
background-color: lightblue;
font-weight: 400;
opacity: 1;
font-weight: 400;
color:black
}
.tags {
display: flex;
gap: 8px;
}
.tag {
border-radius: 16px;
background-color: #ffc6c2;
font-size: 12px;
color: #690D0D;
background-color: #690D0D;
border: 1px solid transparent;
transition: .4s border-color;
cursor: pointer;
}
.tag:hover {
border-color: #bb7676;
}
.tag,
.status,
.edit,
.delete {
padding: 8px 12px;
display: flex;
align-items: center;
justify-content: center;
}
.status.closed {
font-size: 12px;
height: fit-content;
padding: 6px 10px;
background-color: #FFCCCB;
border-radius: 16px;
}
.status.claimed {
font-size: 12px;
height: fit-content;
padding: 6px 10px;
background-color: lightgreen;
border-radius: 16px;
}
</style>
<h3> <%=project.Title%>
</h3>
</a>
<p> <%=project.Description%> </p>
<a href="/project/<%=project.UniqueID%>">
</div>
<% project.Tags.forEach(function(tag) { %>
<div class="tag"><%= tag %></div>
<% }); %>
<nav class="level is-mobile">
<div class="level-left"><small>
<button onclick="loadMoreProjects()"
style="border-radius: 5px;"
class="button bot_right is-small bountybutton has-text-black">View More</button>
</small></div>
</nav>
</div>
</article>
</a>
</section>
<% }); %>
</div>
</body>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- Include jQuery library -->
<div class="bounties">
<% projects.forEach(function(project, index) { %>
<section class="box" style="margin: 1rem;">
<a href="/project/<%=project.UniqueID%>">
<article class="media" style="background: white;">
<div class="media-content">
<div class="content">
<p>
<span style="font-size: 2rem; color: #2d2d2d;margin-left: -2px;">Earn <strong
style="color: #5cb85c">$<%=project.DollarAmount.toLocaleString()%>!</strong></span>
<br>
<span><small><i class="fa-solid fa-clock" style="margin-right: 0.2rem;"></i> Listed <%= getTimePassed(project.ListedDate) %> </small> </span>
<% if(project.Status == 'open') { %>
<div class="status regular tag" style=""><p style="color:black">Open</p></div>
<% } else if(project.Status == 'claimed') { %>
<div class="status claimed tag">Claimed</div>
<% } else if(project.Status == 'closed') { %>
<div class="status closed tag">Closed</div>
<% } else if(project.Status == 'cancelled') { %>
<div class="status closed tag">Cancelled</div>
<% } else if(project.Status == 'completed') { %>
<div class="status claimed tag">Completed</div>
<% } %>
<style>
.status.regular {
font-size: 12px;
height: fit-content;
padding: 6px 10px;
border-radius: 16px;
background-color: lightblue;
font-weight: 400;
opacity: 1;
font-weight: 400;
color:black
}
.tags {
display: flex;
gap: 8px;
}
.tag {
border-radius: 16px;
background-color: #ffc6c2;
font-size: 12px;
color: #690D0D;
background-color: #690D0D;
border: 1px solid transparent;
transition: .4s border-color;
cursor: pointer;
}
.tag:hover {
border-color: #bb7676;
}
.tag,
.status,
.edit,
.delete {
padding: 8px 12px;
display: flex;
align-items: center;
justify-content: center;
}
.status.closed {
font-size: 12px;
height: fit-content;
padding: 6px 10px;
background-color: #FFCCCB;
border-radius: 16px;
}
.status.claimed {
font-size: 12px;
height: fit-content;
padding: 6px 10px;
background-color: lightgreen;
border-radius: 16px;
}
</style>
<h3> <%=project.Title%>
</h3>
</a>
<p> <%=project.Description%> </p>
<a href="/project/<%=project.UniqueID%>">
</div>
<% project.Tags.forEach(function(tag) { %>
<div class="tag"><%= tag %></div>
<% }); %>
<nav class="level is-mobile">
<div class="level-left"><small>
<button style="border-radius: 5px;"
class="button bot_right is-small bountybutton has-text-black">View More</button>
</small></div>
</nav>
</div>
</article>
</a>
</section>
<% }); %>
</div>
</body>
<script>
</script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
function getTimePassed(dateString) {
const date1 = new Date(dateString);
if (isNaN(date1.getTime())) {
return "Invalid date";
}
const now = new Date();
const timeDiff = now.getTime() - date1.getTime(); // Time difference in milliseconds
// Define time units in milliseconds
const oneSecond = 1000;
const oneMinute = 60 * oneSecond;
const oneHour = 60 * oneMinute;
const oneDay = 24 * oneHour;
const oneWeek = 7 * oneDay;
const oneMonth = 30 * oneDay;
const oneYear = 365 * oneDay;
// Determine the appropriate time unit and rounded value
if (timeDiff < oneMinute) {
return Math.round(timeDiff / oneSecond) + " seconds ago";
} else if (timeDiff < oneHour) {
return Math.round(timeDiff / oneMinute) + " minutes ago";
} else if (timeDiff < oneDay) {
return Math.round(timeDiff / oneHour) + " hours ago";
} else if (timeDiff < oneWeek) {
return Math.round(timeDiff / oneDay) + " days ago";
} else if (timeDiff < oneMonth) {
return Math.round(timeDiff / oneWeek) + " weeks ago";
} else if (timeDiff < oneYear) {
return Math.round(timeDiff / oneMonth) + " months ago";
} else {
return Math.round(timeDiff / oneYear) + " years ago";
}
}
alert(getTimePassed)
var PAGE_SIZE = 10;
var page = 1;
var isLoading = false;
const projectContainer = document.querySelector('.bounties');
const observer = new IntersectionObserver((entries) => {
// Check if the target element is intersecting with the viewport
if (entries[0].isIntersecting && !isLoading) {
loadMoreProjects();
}
});
const lastProject = document.querySelector('.bounties section:last-child');
if (lastProject) {
observer.observe(lastProject);
}
function loadMoreProjects() {
const nextPage = page + 1;
// Make an AJAX request to the "/loadmore" endpoint with the next page number
$.ajax({
url: '/loadmore',
method: 'GET',
data: { page: nextPage },
success: function (response) {
const projects = response.projects;
const hasMoreProjects = projects.length >= PAGE_SIZE;
const fragment = document.createDocumentFragment();
projects.forEach(function (project) {
const projectHTML = `
<section class="box" style="margin: 1rem;">
<a href="/project/${project.UniqueID}">
<article class="media" style="background: white;">
<div class="media-content">
<div class="content">
<p>
<span style="font-size: 2rem; color: #2d2d2d;margin-left: -2px;">Earn <strong style="color: #5cb85c">$${project.DollarAmount.toLocaleString()}!</strong></span>
<br>
<span><small><i class="fa-solid fa-clock" style="margin-right: 0.2rem;"></i> Listed ${getTimePassed(project.ListedDate)}</small></span>
${
project.Status === 'open'
? '<div class="status regular tag" style=""><p style="color:black">Open</p></div>'
: project.Status === 'claimed'
? '<div class="status claimed tag">Claimed</div>'
: project.Status === 'closed'
? '<div class="status closed tag">Closed</div>'
: project.Status === 'cancelled'
? '<div class="status closed tag">Cancelled</div>'
: project.Status === 'completed'
? '<div class="status claimed tag">Completed</div>'
: ''
}
<h3>${project.Title}</h3>
</p>
<p>${project.Description}</p>
<a href="/project/${project.UniqueID}">
<div class="tags">
${project.Tags.map((tag) => `<div class="tag">${tag}</div>`).join('')}
</div>
<nav class="level is-mobile">
<div class="level-left">
<small>
<button style="border-radius: 5px;" class="button bot_right is-small bountybutton has-text-black">View More</button>
</small>
</div>
</nav>
</a>
</div>
</div>
</article>
</a>
</section>
`;
const tempElement = document.createElement('div');
tempElement.innerHTML = projectHTML;
fragment.appendChild(tempElement.firstChild);
});
projectContainer.appendChild(fragment);
page = nextPage;
isLoading = false;
if (hasMoreProjects) {
observer.observe(document.querySelector('.bounties section:last-child'));
} else {
observer.disconnect();
}
},
error: function (xhr, status, error) {
console.log('Error:', error);
isLoading = false; // Reset the isLoading flag in case of an error
},
beforeSend: function () {
isLoading = true;
},
});
}
</script>
It fetches from this route
app.get('/loadmore', async function (req, res) {
console.log(req.query.page)
console.log('Load More route accessed');
const PAGE_SIZE = 10; // Make sure this matches the frontend code
const page = req.query.page || 1;
const skip = (page - 1) * PAGE_SIZE;
const openProjects = await projectSchema
.find({ Status: 'open', PaidFor: true })
.sort({ ListedDate: -1 })
.skip(skip)
.limit(PAGE_SIZE);
const otherProjects = await projectSchema
.find({ Status: { $ne: 'open' }, PaidFor: true })
.sort({ ListedDate: -1 })
.skip(skip)
.limit(PAGE_SIZE);
const projects = openProjects.concat(otherProjects);
console.log(projects)
res.json({ projects }); // Send the projects as a JSON object
});
Here are some example projects:
const projects = [
{
_id: new ObjectId("64975f944b1fb2bd347d26ff"),
Category: 'Code',
Title: 'yo',
Lister: 'burningfalco99@gmail.com',
Description: 'yyoyoyooyoyoy',
DollarAmount: 22,
ListingFeesCollected: 5,
Tags: [ 'css', 'html', 'javascript' ],
Applicants: [],
Criteria: 'none',
Details: 'yoyoyoyo',
Status: 'open',
DueDate: 2023-06-24T21:26:44.115Z,
ListedDate: 'Sat Jun 24 2023 14:26:44 GMT-0700 (Pacific Daylight Time)',
Discussion: [],
UniqueID: 'fdsfsdfsdf',
PaidFor: true,
StripeSession: '',
__v: 0
},
{
_id: new ObjectId("64975f944b1fb2bd347d2701"),
Category: 'Code',
Title: 'yo',
Lister: 'burningfalco99@gmail.com',
Description: 'yyoyoyooyoyoy',
DollarAmount: 22,
ListingFeesCollected: 5,
Tags: [ 'css', 'html', 'javascript' ],
Applicants: [],
Criteria: 'none',
Details: 'yoyoyoyo',
Status: 'open',
DueDate: 2023-06-24T21:26:44.200Z,
ListedDate: 'Sat Jun 24 2023 14:26:44 GMT-0700 (Pacific Daylight Time)',
Discussion: [],
UniqueID: 'fdsfsdfsdf',
PaidFor: true,
StripeSession: '',
__v: 0
},
{
_id: new ObjectId("64975f944b1fb2bd347d2707"),
Category: 'Code',
Title: 'yo',
Lister: 'burningfalco99@gmail.com',
Description: 'yyoyoyooyoyoy',
DollarAmount: 22,
ListingFeesCollected: 5,
Tags: [ 'css', 'html', 'javascript' ],
Applicants: [],
Criteria: 'none',
Details: 'yoyoyoyo',
Status: 'open',
DueDate: 2023-06-24T21:26:44.452Z,
ListedDate: 'Sat Jun 24 2023 14:26:44 GMT-0700 (Pacific Daylight Time)',
Discussion: [],
UniqueID: 'fdsfsdfsdf',
PaidFor: true,
StripeSession: '',
__v: 0
},
{
_id: new ObjectId("64975f944b1fb2bd347d2709"),
Category: 'Code',
Title: 'yo',
Lister: 'burningfalco99@gmail.com',
Description: 'yyoyoyooyoyoy',
DollarAmount: 22,
ListingFeesCollected: 5,
Tags: [ 'css', 'html', 'javascript' ],
Applicants: [],
Criteria: 'none',
Details: 'yoyoyoyo',
Status: 'open',
DueDate: 2023-06-24T21:26:44.852Z,
ListedDate: 'Sat Jun 24 2023 14:26:44 GMT-0700 (Pacific Daylight Time)',
Discussion: [],
UniqueID: 'fdsfsdfsdf',
PaidFor: true,
StripeSession: '',
__v: 0
},
{
_id: new ObjectId("64975f944b1fb2bd347d2705"),
Category: 'Code',
Title: 'yo',
Lister: 'burningfalco99@gmail.com',
Description: 'yyoyoyooyoyoy',
DollarAmount: 22,
ListingFeesCollected: 5,
Tags: [ 'css', 'html', 'javascript' ],
Applicants: [],
Criteria: 'none',
Details: 'yoyoyoyo',
Status: 'open',
DueDate: 2023-06-24T21:26:44.368Z,
ListedDate: 'Sat Jun 24 2023 14:26:44 GMT-0700 (Pacific Daylight Time)',
Discussion: [],
UniqueID: 'fdsfsdfsdf',
PaidFor: true,
StripeSession: '',
__v: 0
},
{
_id: new ObjectId("64975f944b1fb2bd347d270b"),
Category: 'Code',
Title: 'yo',
Lister: 'burningfalco99@gmail.com',
Description: 'yyoyoyooyoyoy',
DollarAmount: 22,
ListingFeesCollected: 5,
Tags: [ 'css', 'html', 'javascript' ],
Applicants: [],
Criteria: 'none',
Details: 'yoyoyoyo',
Status: 'open',
DueDate: 2023-06-24T21:26:44.935Z,
ListedDate: 'Sat Jun 24 2023 14:26:44 GMT-0700 (Pacific Daylight Time)',
Discussion: [],
UniqueID: 'fdsfsdfsdf',
PaidFor: true,
StripeSession: '',
__v: 0
},
{
_id: new ObjectId("64975f944b1fb2bd347d2703"),
Category: 'Code',
Title: 'yo',
Lister: 'burningfalco99@gmail.com',
Description: 'yyoyoyooyoyoy',
DollarAmount: 22,
ListingFeesCollected: 5,
Tags: [ 'css', 'html', 'javascript' ],
Applicants: [],
Criteria: 'none',
Details: 'yoyoyoyo',
Status: 'open',
DueDate: 2023-06-24T21:26:44.284Z,
ListedDate: 'Sat Jun 24 2023 14:26:44 GMT-0700 (Pacific Daylight Time)',
Discussion: [],
UniqueID: 'fdsfsdfsdf',
PaidFor: true,
StripeSession: '',
__v: 0
},
{
_id: new ObjectId("64975f934b1fb2bd347d26fb"),
Category: 'Code',
Title: 'yo',
Lister: 'burningfalco99@gmail.com',
Description: 'yyoyoyooyoyoy',
DollarAmount: 22,
ListingFeesCollected: 5,
Tags: [ 'css', 'html', 'javascript' ],
Applicants: [],
Criteria: 'none',
Details: 'yoyoyoyo',
Status: 'open',
DueDate: 2023-06-24T21:26:43.948Z,
ListedDate: 'Sat Jun 24 2023 14:26:43 GMT-0700 (Pacific Daylight Time)',
Discussion: [],
UniqueID: 'fdsfsdfsdf',
PaidFor: true,
StripeSession: '',
__v: 0
},
{
_id: new ObjectId("64975f934b1fb2bd347d26f9"),
Category: 'Code',
Title: 'yo',
Lister: 'burningfalco99@gmail.com',
Description: 'yyoyoyooyoyoy',
DollarAmount: 22,
ListingFeesCollected: 5,
Tags: [ 'css', 'html', 'javascript' ],
Applicants: [],
Criteria: 'none',
Details: 'yoyoyoyo',
Status: 'open',
DueDate: 2023-06-24T21:26:43.862Z,
ListedDate: 'Sat Jun 24 2023 14:26:43 GMT-0700 (Pacific Daylight Time)',
Discussion: [],
UniqueID: 'fdsfsdfsdf',
PaidFor: true,
StripeSession: '',
__v: 0
},
{
_id: new ObjectId("64975f884b1fb2bd347d26f5"),
Category: 'Code',
Title: 'yo',
Lister: 'burningfalco99@gmail.com',
Description: 'yyoyoyooyoyoy',
DollarAmount: 22,
ListingFeesCollected: 5,
Tags: [ 'css', 'html', 'javascript' ],
Applicants: [],
Criteria: 'none',
Details: 'yoyoyoyo',
Status: 'open',
DueDate: 2023-06-24T21:26:32.176Z,
ListedDate: 'Sat Jun 24 2023 14:26:32 GMT-0700 (Pacific Daylight Time)',
Discussion: [],
UniqueID: 'fdsfsdfsdf',
PaidFor: true,
StripeSession: '',
__v: 0
}
]
When I scroll to the bottom of the page, more projects are supposed to load in everytime I reach the bottom of the rendered projects.
However, if I reach the bottom of the page, it console.logs "Load More route accessed", meaning that the route has been accessed, and the code is running. This happens sometimes only. However, even with the route being accessed, the new projects are not rendered.
How do I fix this, and also ensure new projects are rendered everytime I reach the bottom of the current projects.
I have been trying to fix this for weeks, so I appreciate your time on helping me.
答案1
得分: 0
section
元素未附加,因为 tempElement.firstChild
实际上是模板文字中的换行字符,所以尝试使用 firstElementChild
代替以获取 section
HTML 元素:
尝试替换
fragment.appendChild(tempElement.firstChild);
为
fragment.appendChild(tempElement.firstElementChild);
<br>
然而,快速滚动会导致问题:快速滚动时,可能不会加载,因为观察者是异步的,所以可能尚未捕获到最后的 section
,在这种情况下请参阅:https://stackoverflow.com/questions/61951380/intersection-observer-fails-sometimes-when-i-scroll-fast
英文:
The section
element isn't appended, because tempElement.firstChild
is actually a newline character from template literal, so try using firstElementChild
instead to get the section
HTML element:
try replacing
fragment.appendChild(tempElement.firstChild);
with
fragment.appendChild(tempElement.firstElementChild);
<br>
However, fast scrolling will cause problems: when scrolling fast, it might not load, because observer is async, so it might not catch the last section
yet, in that case see: https://stackoverflow.com/questions/61951380/intersection-observer-fails-sometimes-when-i-scroll-fast
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论