CS50W Project network, can't figure how to implement the Paginator
I've been trying to implement the paginator function for about two months now. I've tried many different approaches, but they always lead to new bugs.
In views.py, I load the posts and send them to JavaScript. In loadPosts and loadProfile, I pass the fetch function as a parameter to the buttons. Everything else works fine. The buttons call the fetch function, and the posts are displayed.
The issue is: once I load the second page of profile posts, then switch to loadPosts and click "next" again, it loads the profile posts instead. I’ve already tried using removeEventListener and flags, but I couldn’t figure out how to properly reset the event listener when switching between the functions.
[06/Jun/2025 09:01:10] "GET /post?start=0&end=9 HTTP/1.1" 200 825 [06/Jun/2025 09:01:10] "GET /post/new?start=0&end=9 HTTP/1.1" 200 810
// Switch between the pages:
document.querySelector("#profile-link").addEventListener('click', function(event) {
// Top left username, to load the profile
loadProfile(loggedInUsername)
});
document.querySelector("#index").addEventListener('click', function(event) {
event.preventDefault();
loadPosts()
});
@csrf_exempt
def post_view(request, username = None):
if request.method == "GET":
# Loading all posts
if username == None:
posts = Post.objects.all().order_by('-date')
start = int(request.GET.get("start") or 0 )
end = int(request.GET.get("end") or (start + 9))
posts_in_range = posts[start:end+1].values("text","date","user__username")
return JsonResponse({"posts": list(posts_in_range)})
else:
# Loading a profile
user = User.objects.get(username=username)
user_id = user.id
posts = Post.objects.filter(user_id=user_id).order_by('-date')
start = int(request.GET.get("start") or 0 )
end = int(request.GET.get("end") or (start + 9))
posts_in_range = posts[start:end+1].values("text","date","user__username")
return JsonResponse({"posts": list(posts_in_range)})
// Loads all the posts on the All Posts page
function loadPosts() {
let counter = 1;
let start = (page - 1) * 10;
let end = start + 9;
if (page < 1) {
page = 1
}
// Fetch all posts
fetch(`/post?start=${start}&end=${end}`,null)
.then(response => response.json())
.then(data => {
buttons(counter, `/post?start=${start}&end=${end}`)
// Hidding buttons and content
document.getElementById("slider").style.display = "none";
document.querySelector("#following").innerHTML = "";
document.querySelector("#posts").innerHTML = "";
document.getElementById("new-post-form").style.display = "block";
// buttons next and previous
data.posts.forEach(add_Post);
})
}
// Loading a profile page
function loadProfile(username, loggedInUsername) {
let counter = 1;
let start = (page - 1) * 10;
let end = start + 9;
if (page < 1) {
page = 1
}
// Fetch profile
fetch(`/post/${username}?start=${start}&end=${end}`)
.then(response => response.json())
.then(data => {
console.log(username)
buttons(counter, `/post/${username}?start=${start}&end=${end}`, username)
document.getElementById("slider").style.display = "none";
document.querySelector("#following").innerHTML = "";
document.getElementById("new-post-form").style.display = "none";
document.querySelector("#posts").innerHTML = "";
// Checks if a username is already followed
checkFollow(username)
// Check if the logged in user wants to see his own profile
if (username === loggedInUsername) {
// Hide the follow function so user cannot follow himself
document.getElementById("slider").style.display = "none";
// Loads posts
if (data.posts.length > 0) {
data.posts.forEach(add_Post);
}
} else {
// Load profile content
document.getElementById("slider").style.display = "block";
const checkbox = document.querySelector('.switch input[type="checkbox"]');
checkbox.addEventListener('change', function(event) {
handleCheckboxChange(username);
});
if (data.posts.length > 0) {
data.posts.forEach(add_Post);
}
}
})
}
function buttons(counter, url, username) {
const previous = document.getElementById("previous");
const next = document.getElementById("next");
console.log(username)
// If no username fetch all posts
if (!username) {
function handleNextClick() {
counter++;
start = (counter - 1) * 10;
end = start + 9;
const newUrl = `/post?start=${start}&end=${end}`
load(counter, newUrl, start, end);
}
function handlePreviousClick() {
counter--;
start = (counter - 1) * 10;
end = start + 9;
const newUrl = `/post?start=${start}&end=${end}`
load(counter, newUrl, start, end);
}
}
// load profile
else {
function handleNextClick() {
counter++;
start = (counter - 1) * 10;
end = start + 9;
const newUrl = `/post/${username}?start=${start}&end=${end}`
load(counter, newUrl, start, end);
}
function handlePreviousClick() {
counter--;
start = (counter - 1) * 10;
end = start + 9;
const newUrl = `/post/${username}?start=${start}&end=${end}`
load(counter, newUrl, start, end);
}
}
function handleClick(event) {
if (event.target.id === "next") {
handleNextClick();
}
else if (event.target.id === "previous") {
handlePreviousClick();
}
}
fetch(url)
.then(response => response.json())
.then(data => {
pageContainer.removeEventListener("click", handleClick);
pageContainer.addEventListener("click", handleClick);
});
}
// Loads the post after being called by buttons
function load(page, newUrl, start, end) {
console.log(load)
fetch(newUrl)
.then(response => response.json())
.then(data => {
// Clear previous posts
document.querySelector("#posts").innerHTML = "";
if (data.posts.length > 0) {
data.posts.forEach(add_Post);
}
});
}
Check out the Django pagination class for some inspiration (or just use it directly :) ):
https://github.com/django/django/blob/main/django/core/paginator.py