JavaScript Script Issue for Dynamic Video Playback

I’m experiencing an issue with my JavaScript script that is supposed to manage video playback on my platform. Currently, the script works correctly for video elements already present on the page, but it does not account for new video elements that are dynamically loaded. None of the scripts work for these new elements.

Dynamic Loading: Videos are added to the page via AJAX when a user scrolls down.
Using IntersectionObserver: I’m attempting to start or stop video playback based on their visibility using the IntersectionObserver.

Problems Encountered

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>No Playback for New Elements: When new video elements are loaded, the script does not work for these.
Complete Script Non-Functional: None of the script seems to function for these new elements.
</code>
<code>No Playback for New Elements: When new video elements are loaded, the script does not work for these. Complete Script Non-Functional: None of the script seems to function for these new elements. </code>
No Playback for New Elements: When new video elements are loaded, the script does not work for these.
Complete Script Non-Functional: None of the script seems to function for these new elements.

What can I do to ensure that the script also works for newly loaded video elements?
Are there best practices I should follow to correctly observe these new elements?

My JS:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>document.addEventListener('DOMContentLoaded', () => {
let currentVideo = null;
const pulseContainer = document.getElementById('pulse-container');
let currentPage = 1;
let loading = false;
let visibleVideoCount = 0;
function handleVideoPlayback(entries) {
entries.forEach(entry => {
const video = entry.target;
if (entry.isIntersecting) {
if (currentVideo !== video) {
video.play();
video.loop = true;
if (currentVideo) {
currentVideo.pause();
}
currentVideo = video;
}
visibleVideoCount++;
console.log(visibleVideoCount);
} else {
if (currentVideo === video) {
currentVideo = null;
}
video.pause();
}
});
// Vérifiez si le compteur de vidéos visibles atteint 5
if (visibleVideoCount >= 5) {
console.log('loadmore please');
loadMoreContent(); // Charge plus de contenu
visibleVideoCount = 0; // Réinitialise le compteur
}
}
const observer = new IntersectionObserver(handleVideoPlayback, {
root: null,
rootMargin: '0px',
threshold: 0.5
});
const videos = document.querySelectorAll('.pulse-video');
videos.forEach(video => {
observer.observe(video);
video.addEventListener('error', (e) => {
console.error('Erreur de chargement de la vidéo:', e);
});
video.src = video.getAttribute('data-src');
video.load();
});
function toggleGlobalSound() {
const newMutedState = !Array.from(videos).some(video => video.muted);
videos.forEach(video => {
video.muted = newMutedState;
});
const globalSoundButtons = document.querySelectorAll('#global-sound-toggle i');
globalSoundButtons.forEach(icon => {
icon.classList.toggle('fa-volume-xmark', newMutedState);
icon.classList.toggle('fa-volume-high', !newMutedState);
});
}
const globalSoundButtons = document.querySelectorAll('#global-sound-toggle');
globalSoundButtons.forEach(button => {
button.addEventListener('click', toggleGlobalSound);
});
function setupVideoClickHandler() {
const videos = document.querySelectorAll('.pulse-video'); // Récupère les vidéos à chaque appel
videos.forEach(video => {
video.addEventListener('click', () => {
video.paused ? video.play() : video.pause();
if (currentVideo && currentVideo !== video) {
currentVideo.pause();
}
currentVideo = video;
});
});
}
function handleVisibilityChange() {
if (document.hidden && currentVideo) {
currentVideo.pause();
} else if (!document.hidden && currentVideo) {
currentVideo.play();
}
}
const artistContents = document.querySelectorAll('.artist-content');
artistContents.forEach(content => {
const toggleButton = content.querySelector('.toggle-description');
if (toggleButton) {
toggleButton.addEventListener('click', () => {
content.classList.toggle('open');
});
}
});
const allArtistElements = document.querySelectorAll('.all_artist'); // Pour plusieurs artistes
allArtistElements.forEach(function(artistContent) {
const toggleButton = artistContent.querySelector('.toggle-description');
const descriptionContent = artistContent.querySelector('.description-content');
// Fonction pour ajuster la hauteur de .all_artist.open
function adjustHeight() {
const descriptionHeight = descriptionContent.scrollHeight; // Hauteur réelle du contenu
const additionalHeight = 0; // Hauteur supplémentaire pour que ça monte plus
artistContent.style.height = `${descriptionHeight + additionalHeight}px`; // Ajuste la hauteur en fonction du contenu
artistContent.style.transform = `translateY(-${descriptionHeight + additionalHeight}px)`;
}
// Fonction pour ouvrir et fermer le contenu
function toggleArtistContent() {
artistContent.classList.toggle('open');
if (artistContent.classList.contains('open')) {
descriptionContent.style.transform = 'translateY(0)'; // Annule le translateY
descriptionContent.style.opacity = '1'; // Affiche le contenu
descriptionContent.style.visibility = 'visible'; // Rend le contenu visible
adjustHeight(); // Ajuste la hauteur de .all_artist.open
} else {
descriptionContent.style.transform = 'translateY(-50px)'; // Cache l'élément
descriptionContent.style.opacity = '0'; // Rend le contenu invisible
descriptionContent.style.visibility = 'hidden'; // Cache le contenu
artistContent.style.height = 'auto'; // Réinitialise la hauteur
artistContent.style.transform = `translateY(0)`; // Réinitialise la position
}
}
// Écouteur d'événement sur le bouton pour basculer l'affichage
toggleButton.addEventListener('click', toggleArtistContent);
});
document.addEventListener('visibilitychange', handleVisibilityChange);
function adjustVideoSize() {
videos.forEach(video => {
video.style.width = '100%';
video.style.height = '100%';
video.style.objectFit = 'cover';
});
}
function preloadVideos() {
const videos = document.querySelectorAll('.pulse-video'); // Récupère les vidéos à chaque appel
videos.forEach(video => {
const rect = video.getBoundingClientRect();
if (rect.top < window.innerHeight && rect.bottom > 0) {
if (video.src === '') {
video.src = video.getAttribute('data-src');
video.load();
}
}
observer.observe(video); // Assure-toi que chaque vidéo est observée
});
}
const loadMoreUrl = '/pulses/load-more-pulses/';
function loadMoreContent() {
console.log('Trying to load more content...');
if (loading) return;
loading = true;
const url = `/pulses/load-more-pulses/?page=${currentPage}`;
fetch(url)
.then(response => {
console.log('Response status:', response.status);
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
console.log('Data received:', data);
if (data.pulse_data) {
data.pulse_data.forEach(pulse => {
pulseContainer.insertAdjacentHTML('beforeend', pulse.html);
});
currentPage++;
initializeNewElements()
}
})
.catch(error => {
console.error('Error loading more content:', error);
})
.finally(() => {
loading = false;
});
}
// Appelle les fonctions au chargement initial
preloadVideos();
function setupInteractionButtons() {
const likeButtons = document.querySelectorAll('.like-button');
const shareButtons = document.querySelectorAll('.share-button');
likeButtons.forEach(button => {
button.addEventListener('click', () => {
const pulseId = button.dataset.pulseId;
fetch('{% url "pulses:toggle_like" %}', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-CSRFToken': getCookie('csrftoken')
},
body: new URLSearchParams({ 'pulse_id': pulseId })
})
.then(response => response.json())
.then(data => {
if (data.error) {
alert(data.error);
} else {
button.querySelector('i').classList.toggle('fa-solid', data.liked);
button.querySelector('i').classList.toggle('fa-regular', !data.liked);
button.querySelector('i').style.color = data.liked ? '#d20000' : 'floralwhite';
button.querySelector('.like-count').textContent = data.like_count;
}
})
.catch(error => console.error('Error:', error));
});
});
shareButtons.forEach(button => {
button.addEventListener('click', () => {
const pulseId = button.dataset.pulseId;
fetch('{% url "pulses:share_pulse" %}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCookie('csrftoken')
},
body: JSON.stringify({ pulse_id: pulseId })
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.querySelector(`.share-count[data-pulse-id="${pulseId}"]`).textContent = data.share_count;
navigator.clipboard.writeText(data.share_url)
.then(() => {
alert('Lien copié!');
})
.catch(err => {
console.error('Erreur lors de la copie du lien:', err);
});
}
})
.catch(error => console.error('Error:', error));
});
});
}
document.querySelectorAll('.toggle-comments').forEach(button => {
button.addEventListener('click', () => {
const commentsSection = button.closest('.pulse_item').querySelector('.comments-section');
commentsSection.style.display = commentsSection.style.display === 'none' || commentsSection.style.display === '' ? 'flex' : 'none';
});
});
setupVideoClickHandler();
setupInteractionButtons();
adjustVideoSize();
preloadVideos();
});
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let cookie of cookies) {
cookie = cookie.trim();
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function loadScript(scriptUrl) {
const script = document.createElement('script');
script.src = scriptUrl;
script.type = 'text/javascript';
document.body.appendChild(script);
}
function initializeNewElements() {
const videos = document.querySelectorAll('.pulse-video');
if (!videos.length) return; // Vérification de la présence de vidéos
videos.forEach(video => {
observer.observe(video);
});
setupInteractionButtons(); // Ajouter les interactions aux nouveaux boutons
}
</code>
<code>document.addEventListener('DOMContentLoaded', () => { let currentVideo = null; const pulseContainer = document.getElementById('pulse-container'); let currentPage = 1; let loading = false; let visibleVideoCount = 0; function handleVideoPlayback(entries) { entries.forEach(entry => { const video = entry.target; if (entry.isIntersecting) { if (currentVideo !== video) { video.play(); video.loop = true; if (currentVideo) { currentVideo.pause(); } currentVideo = video; } visibleVideoCount++; console.log(visibleVideoCount); } else { if (currentVideo === video) { currentVideo = null; } video.pause(); } }); // Vérifiez si le compteur de vidéos visibles atteint 5 if (visibleVideoCount >= 5) { console.log('loadmore please'); loadMoreContent(); // Charge plus de contenu visibleVideoCount = 0; // Réinitialise le compteur } } const observer = new IntersectionObserver(handleVideoPlayback, { root: null, rootMargin: '0px', threshold: 0.5 }); const videos = document.querySelectorAll('.pulse-video'); videos.forEach(video => { observer.observe(video); video.addEventListener('error', (e) => { console.error('Erreur de chargement de la vidéo:', e); }); video.src = video.getAttribute('data-src'); video.load(); }); function toggleGlobalSound() { const newMutedState = !Array.from(videos).some(video => video.muted); videos.forEach(video => { video.muted = newMutedState; }); const globalSoundButtons = document.querySelectorAll('#global-sound-toggle i'); globalSoundButtons.forEach(icon => { icon.classList.toggle('fa-volume-xmark', newMutedState); icon.classList.toggle('fa-volume-high', !newMutedState); }); } const globalSoundButtons = document.querySelectorAll('#global-sound-toggle'); globalSoundButtons.forEach(button => { button.addEventListener('click', toggleGlobalSound); }); function setupVideoClickHandler() { const videos = document.querySelectorAll('.pulse-video'); // Récupère les vidéos à chaque appel videos.forEach(video => { video.addEventListener('click', () => { video.paused ? video.play() : video.pause(); if (currentVideo && currentVideo !== video) { currentVideo.pause(); } currentVideo = video; }); }); } function handleVisibilityChange() { if (document.hidden && currentVideo) { currentVideo.pause(); } else if (!document.hidden && currentVideo) { currentVideo.play(); } } const artistContents = document.querySelectorAll('.artist-content'); artistContents.forEach(content => { const toggleButton = content.querySelector('.toggle-description'); if (toggleButton) { toggleButton.addEventListener('click', () => { content.classList.toggle('open'); }); } }); const allArtistElements = document.querySelectorAll('.all_artist'); // Pour plusieurs artistes allArtistElements.forEach(function(artistContent) { const toggleButton = artistContent.querySelector('.toggle-description'); const descriptionContent = artistContent.querySelector('.description-content'); // Fonction pour ajuster la hauteur de .all_artist.open function adjustHeight() { const descriptionHeight = descriptionContent.scrollHeight; // Hauteur réelle du contenu const additionalHeight = 0; // Hauteur supplémentaire pour que ça monte plus artistContent.style.height = `${descriptionHeight + additionalHeight}px`; // Ajuste la hauteur en fonction du contenu artistContent.style.transform = `translateY(-${descriptionHeight + additionalHeight}px)`; } // Fonction pour ouvrir et fermer le contenu function toggleArtistContent() { artistContent.classList.toggle('open'); if (artistContent.classList.contains('open')) { descriptionContent.style.transform = 'translateY(0)'; // Annule le translateY descriptionContent.style.opacity = '1'; // Affiche le contenu descriptionContent.style.visibility = 'visible'; // Rend le contenu visible adjustHeight(); // Ajuste la hauteur de .all_artist.open } else { descriptionContent.style.transform = 'translateY(-50px)'; // Cache l'élément descriptionContent.style.opacity = '0'; // Rend le contenu invisible descriptionContent.style.visibility = 'hidden'; // Cache le contenu artistContent.style.height = 'auto'; // Réinitialise la hauteur artistContent.style.transform = `translateY(0)`; // Réinitialise la position } } // Écouteur d'événement sur le bouton pour basculer l'affichage toggleButton.addEventListener('click', toggleArtistContent); }); document.addEventListener('visibilitychange', handleVisibilityChange); function adjustVideoSize() { videos.forEach(video => { video.style.width = '100%'; video.style.height = '100%'; video.style.objectFit = 'cover'; }); } function preloadVideos() { const videos = document.querySelectorAll('.pulse-video'); // Récupère les vidéos à chaque appel videos.forEach(video => { const rect = video.getBoundingClientRect(); if (rect.top < window.innerHeight && rect.bottom > 0) { if (video.src === '') { video.src = video.getAttribute('data-src'); video.load(); } } observer.observe(video); // Assure-toi que chaque vidéo est observée }); } const loadMoreUrl = '/pulses/load-more-pulses/'; function loadMoreContent() { console.log('Trying to load more content...'); if (loading) return; loading = true; const url = `/pulses/load-more-pulses/?page=${currentPage}`; fetch(url) .then(response => { console.log('Response status:', response.status); if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then(data => { console.log('Data received:', data); if (data.pulse_data) { data.pulse_data.forEach(pulse => { pulseContainer.insertAdjacentHTML('beforeend', pulse.html); }); currentPage++; initializeNewElements() } }) .catch(error => { console.error('Error loading more content:', error); }) .finally(() => { loading = false; }); } // Appelle les fonctions au chargement initial preloadVideos(); function setupInteractionButtons() { const likeButtons = document.querySelectorAll('.like-button'); const shareButtons = document.querySelectorAll('.share-button'); likeButtons.forEach(button => { button.addEventListener('click', () => { const pulseId = button.dataset.pulseId; fetch('{% url "pulses:toggle_like" %}', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-CSRFToken': getCookie('csrftoken') }, body: new URLSearchParams({ 'pulse_id': pulseId }) }) .then(response => response.json()) .then(data => { if (data.error) { alert(data.error); } else { button.querySelector('i').classList.toggle('fa-solid', data.liked); button.querySelector('i').classList.toggle('fa-regular', !data.liked); button.querySelector('i').style.color = data.liked ? '#d20000' : 'floralwhite'; button.querySelector('.like-count').textContent = data.like_count; } }) .catch(error => console.error('Error:', error)); }); }); shareButtons.forEach(button => { button.addEventListener('click', () => { const pulseId = button.dataset.pulseId; fetch('{% url "pulses:share_pulse" %}', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') }, body: JSON.stringify({ pulse_id: pulseId }) }) .then(response => response.json()) .then(data => { if (data.success) { document.querySelector(`.share-count[data-pulse-id="${pulseId}"]`).textContent = data.share_count; navigator.clipboard.writeText(data.share_url) .then(() => { alert('Lien copié!'); }) .catch(err => { console.error('Erreur lors de la copie du lien:', err); }); } }) .catch(error => console.error('Error:', error)); }); }); } document.querySelectorAll('.toggle-comments').forEach(button => { button.addEventListener('click', () => { const commentsSection = button.closest('.pulse_item').querySelector('.comments-section'); commentsSection.style.display = commentsSection.style.display === 'none' || commentsSection.style.display === '' ? 'flex' : 'none'; }); }); setupVideoClickHandler(); setupInteractionButtons(); adjustVideoSize(); preloadVideos(); }); function getCookie(name) { let cookieValue = null; if (document.cookie && document.cookie !== '') { const cookies = document.cookie.split(';'); for (let cookie of cookies) { cookie = cookie.trim(); if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } function loadScript(scriptUrl) { const script = document.createElement('script'); script.src = scriptUrl; script.type = 'text/javascript'; document.body.appendChild(script); } function initializeNewElements() { const videos = document.querySelectorAll('.pulse-video'); if (!videos.length) return; // Vérification de la présence de vidéos videos.forEach(video => { observer.observe(video); }); setupInteractionButtons(); // Ajouter les interactions aux nouveaux boutons } </code>
document.addEventListener('DOMContentLoaded', () => {
        let currentVideo = null;  
        const pulseContainer = document.getElementById('pulse-container');
        let currentPage = 1;
        let loading = false;
        let visibleVideoCount = 0;

        function handleVideoPlayback(entries) {
            entries.forEach(entry => {
                const video = entry.target;
                if (entry.isIntersecting) {
                    if (currentVideo !== video) {
                        video.play();
                        video.loop = true;
                        if (currentVideo) {
                            currentVideo.pause();
                        }
                        currentVideo = video;
                    }
                    visibleVideoCount++;
                    console.log(visibleVideoCount);
                } else {
                    if (currentVideo === video) {
                        currentVideo = null;  
                    }
                    video.pause();
                }
            });
    
            // Vérifiez si le compteur de vidéos visibles atteint 5
            if (visibleVideoCount >= 5) {
                console.log('loadmore please');
                loadMoreContent(); // Charge plus de contenu
                visibleVideoCount = 0; // Réinitialise le compteur
            }
        }  
    
        const observer = new IntersectionObserver(handleVideoPlayback, {
            root: null,
            rootMargin: '0px',
            threshold: 0.5
        });
    
        const videos = document.querySelectorAll('.pulse-video');
        videos.forEach(video => {
            observer.observe(video);
            video.addEventListener('error', (e) => {
                console.error('Erreur de chargement de la vidéo:', e);
            });
            video.src = video.getAttribute('data-src');
            video.load();
           
        });
    
        function toggleGlobalSound() {
            const newMutedState = !Array.from(videos).some(video => video.muted);
            videos.forEach(video => {
                video.muted = newMutedState;
            });
            const globalSoundButtons = document.querySelectorAll('#global-sound-toggle i');
            globalSoundButtons.forEach(icon => {
                icon.classList.toggle('fa-volume-xmark', newMutedState);
                icon.classList.toggle('fa-volume-high', !newMutedState);
            });
        }
        
        const globalSoundButtons = document.querySelectorAll('#global-sound-toggle');
        globalSoundButtons.forEach(button => {
            button.addEventListener('click', toggleGlobalSound);
        });
    
        function setupVideoClickHandler() {
            const videos = document.querySelectorAll('.pulse-video'); // Récupère les vidéos à chaque appel
            videos.forEach(video => {
                video.addEventListener('click', () => {
                    video.paused ? video.play() : video.pause();
                    if (currentVideo && currentVideo !== video) {
                        currentVideo.pause();
                    }
                    currentVideo = video;
                });
            });
        }
    
        function handleVisibilityChange() {
            if (document.hidden && currentVideo) {
                currentVideo.pause();
            } else if (!document.hidden && currentVideo) {
                currentVideo.play();
            }
            
        }
        const artistContents = document.querySelectorAll('.artist-content');

        artistContents.forEach(content => {
            const toggleButton = content.querySelector('.toggle-description');

            if (toggleButton) {
                toggleButton.addEventListener('click', () => {
                    content.classList.toggle('open');
                });
            }
        });
        const allArtistElements = document.querySelectorAll('.all_artist'); // Pour plusieurs artistes
        
        allArtistElements.forEach(function(artistContent) {
            const toggleButton = artistContent.querySelector('.toggle-description');
            const descriptionContent = artistContent.querySelector('.description-content');
            
            // Fonction pour ajuster la hauteur de .all_artist.open
            function adjustHeight() {
                const descriptionHeight = descriptionContent.scrollHeight; // Hauteur réelle du contenu
                const additionalHeight = 0; // Hauteur supplémentaire pour que ça monte plus
                artistContent.style.height = `${descriptionHeight + additionalHeight}px`; // Ajuste la hauteur en fonction du contenu
                artistContent.style.transform = `translateY(-${descriptionHeight + additionalHeight}px)`; 
            }
            
            // Fonction pour ouvrir et fermer le contenu
            function toggleArtistContent() {
                artistContent.classList.toggle('open');
                if (artistContent.classList.contains('open')) {
                    descriptionContent.style.transform = 'translateY(0)'; // Annule le translateY
                    descriptionContent.style.opacity = '1'; // Affiche le contenu
                    descriptionContent.style.visibility = 'visible'; // Rend le contenu visible
                    adjustHeight(); // Ajuste la hauteur de .all_artist.open
                } else {
                    descriptionContent.style.transform = 'translateY(-50px)'; // Cache l'élément
                    descriptionContent.style.opacity = '0'; // Rend le contenu invisible
                    descriptionContent.style.visibility = 'hidden'; // Cache le contenu
                    artistContent.style.height = 'auto'; // Réinitialise la hauteur
                    artistContent.style.transform = `translateY(0)`; // Réinitialise la position
                }
            }
            
            // Écouteur d'événement sur le bouton pour basculer l'affichage
            toggleButton.addEventListener('click', toggleArtistContent);
        });
    
        document.addEventListener('visibilitychange', handleVisibilityChange);
    
        function adjustVideoSize() {
            videos.forEach(video => {
                video.style.width = '100%';
                video.style.height = '100%';
                video.style.objectFit = 'cover';
            });
        }
    
        function preloadVideos() {
            const videos = document.querySelectorAll('.pulse-video'); // Récupère les vidéos à chaque appel
            videos.forEach(video => {
                const rect = video.getBoundingClientRect();
                if (rect.top < window.innerHeight && rect.bottom > 0) {
                    if (video.src === '') {
                        video.src = video.getAttribute('data-src');
                        video.load();
                    }
                }
                observer.observe(video); // Assure-toi que chaque vidéo est observée
            });
        }
        const loadMoreUrl = '/pulses/load-more-pulses/';
        function loadMoreContent() {
            console.log('Trying to load more content...');
            if (loading) return;
            loading = true;
    
            const url = `/pulses/load-more-pulses/?page=${currentPage}`;
            fetch(url)
                .then(response => {
                    console.log('Response status:', response.status);
                    if (!response.ok) {
                        throw new Error('Network response was not ok');
                    }
                    return response.json();
                })
                .then(data => {
                    console.log('Data received:', data);
                    if (data.pulse_data) {
                        data.pulse_data.forEach(pulse => {
                            pulseContainer.insertAdjacentHTML('beforeend', pulse.html);
                        });
                        currentPage++;
                        initializeNewElements()
                       
                    }
                })
                .catch(error => {
                    console.error('Error loading more content:', error);
                })
                .finally(() => {
                    loading = false;
                });
        }
    
        // Appelle les fonctions au chargement initial
        preloadVideos();
        
       
    
        function setupInteractionButtons() {
            const likeButtons = document.querySelectorAll('.like-button');
            const shareButtons = document.querySelectorAll('.share-button');
    
            likeButtons.forEach(button => {
                button.addEventListener('click', () => {
                    const pulseId = button.dataset.pulseId;
                    fetch('{% url "pulses:toggle_like" %}', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/x-www-form-urlencoded',
                            'X-CSRFToken': getCookie('csrftoken')
                        },
                        body: new URLSearchParams({ 'pulse_id': pulseId })
                    })
                    .then(response => response.json())
                    .then(data => {
                        if (data.error) {
                            alert(data.error);
                        } else {
                            button.querySelector('i').classList.toggle('fa-solid', data.liked);
                            button.querySelector('i').classList.toggle('fa-regular', !data.liked);
                            button.querySelector('i').style.color = data.liked ? '#d20000' : 'floralwhite';
                            button.querySelector('.like-count').textContent = data.like_count;
                        }
                    })
                    .catch(error => console.error('Error:', error));
                });
            });
    
            shareButtons.forEach(button => {
                button.addEventListener('click', () => {
                    const pulseId = button.dataset.pulseId;
                    fetch('{% url "pulses:share_pulse" %}', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'X-CSRFToken': getCookie('csrftoken')
                        },
                        body: JSON.stringify({ pulse_id: pulseId })
                    })
                    .then(response => response.json())
                    .then(data => {
                        if (data.success) {
                            document.querySelector(`.share-count[data-pulse-id="${pulseId}"]`).textContent = data.share_count;
                            navigator.clipboard.writeText(data.share_url)
                                .then(() => {
                                    alert('Lien copié!');
                                })
                                .catch(err => {
                                    console.error('Erreur lors de la copie du lien:', err);
                                });
                        }
                    })
                    .catch(error => console.error('Error:', error));
                });
            });
        }
    
        document.querySelectorAll('.toggle-comments').forEach(button => {
            button.addEventListener('click', () => {
                const commentsSection = button.closest('.pulse_item').querySelector('.comments-section');
                commentsSection.style.display = commentsSection.style.display === 'none' || commentsSection.style.display === '' ? 'flex' : 'none';
            });
        });
    
        setupVideoClickHandler();
        setupInteractionButtons();
        adjustVideoSize();
        preloadVideos();
    });
    
    function getCookie(name) {
        let cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            const cookies = document.cookie.split(';');
            for (let cookie of cookies) {
                cookie = cookie.trim();
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }


    function loadScript(scriptUrl) {
        const script = document.createElement('script');
        script.src = scriptUrl;
        script.type = 'text/javascript';
        document.body.appendChild(script);
    }
    
    
    function initializeNewElements() {
        const videos = document.querySelectorAll('.pulse-video');
        if (!videos.length) return; // Vérification de la présence de vidéos
    
        videos.forEach(video => {
            observer.observe(video);
        });
        
        setupInteractionButtons(); // Ajouter les interactions aux nouveaux boutons
    }
 

My global HTML:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code> <div class="all_pulse">
<div class="pulse_title">Pulse</div>
<div class="pulse_contains" id="pulse-container">
{% for pulse in pulses %}
{% include 'pages/partial-pulse.html' with pulse=pulse %}
{% endfor %}
</div>
<div class="bar">
<div class="bar-item">
<a href="{% url 'content:index' %}" style="color:white;"><i class="fa-solid fa-house"></i></a>
<a href="{% url 'beats:new_explore' %}" style="color:white;"><i class="fa-solid fa-magnifying-glass"></i></a>
<a href="{% url 'pulses:pulse' %}" style="color:white;"><i class="fa-solid fa-compact-disc fa-lg" style="margin-top:5.5px;"></i></a>
<a href="{% url 'accounts:conversations' %}" style="color:white;"><i class="fa-solid fa-message"></i></a>
<a href="{% url 'accounts:profile' %}" style="color:white;"><i class="fa-solid fa-user"></i></a>
</div>
</div>
</div>
</code>
<code> <div class="all_pulse"> <div class="pulse_title">Pulse</div> <div class="pulse_contains" id="pulse-container"> {% for pulse in pulses %} {% include 'pages/partial-pulse.html' with pulse=pulse %} {% endfor %} </div> <div class="bar"> <div class="bar-item"> <a href="{% url 'content:index' %}" style="color:white;"><i class="fa-solid fa-house"></i></a> <a href="{% url 'beats:new_explore' %}" style="color:white;"><i class="fa-solid fa-magnifying-glass"></i></a> <a href="{% url 'pulses:pulse' %}" style="color:white;"><i class="fa-solid fa-compact-disc fa-lg" style="margin-top:5.5px;"></i></a> <a href="{% url 'accounts:conversations' %}" style="color:white;"><i class="fa-solid fa-message"></i></a> <a href="{% url 'accounts:profile' %}" style="color:white;"><i class="fa-solid fa-user"></i></a> </div> </div> </div> </code>
   <div class="all_pulse">
    <div class="pulse_title">Pulse</div>
    <div class="pulse_contains" id="pulse-container">
        {% for pulse in pulses %}
            {% include 'pages/partial-pulse.html' with pulse=pulse %}
        {% endfor %}
    </div>
    <div class="bar">
        <div class="bar-item">
            <a href="{% url 'content:index' %}" style="color:white;"><i class="fa-solid fa-house"></i></a>
            <a href="{% url 'beats:new_explore' %}" style="color:white;"><i class="fa-solid fa-magnifying-glass"></i></a>
            <a href="{% url 'pulses:pulse' %}" style="color:white;"><i class="fa-solid fa-compact-disc fa-lg" style="margin-top:5.5px;"></i></a>
            <a href="{% url 'accounts:conversations' %}" style="color:white;"><i class="fa-solid fa-message"></i></a>
            <a href="{% url 'accounts:profile' %}" style="color:white;"><i class="fa-solid fa-user"></i></a>
        </div>
    </div>
</div>   

My HTML which is implemented with ajax:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>{% load static %}
<script src="{% static 'js/new_pulse.js' %}"></script>
<div class="pulse_item">
<div class="video-wrapper">
<video data-src="{{ pulse.video.url }}" class="pulse-video" src="{{ pulse.video.url }}" muted playsinline></video>
</div>
<div class="comments-section" style="display: none;">
<div class="comment-list">
<h5 class="title_comments">Comments</h5>
{% if pulse.comments.all %}
{% for comment in pulse.comments.all %}
<div class="comment">
<strong>{{ comment.user.username }}:</strong>
<p>{{ comment.text }}</p>
<small style="color:grey;">{{ comment.created_at|date:"d M Y, H:i" }}</small>
</div>
{% endfor %}
{% else %}
<p style="color:white;">Aucun commentaire</p>
{% endif %}
</div>
<textarea class="comment-input" placeholder="Écrivez un commentaire..."></textarea>
<button class="button-up" data-pulse-id="{{ pulse.id }}">Envoyer</button>
</div>
<div class="interacts">
<div class="item-orga">
<button class="like-button" data-pulse-id="{{ pulse.id }}" style="background-color:transparent;color:white;border:none;">
<i class="fa-heart {% if pulse.liked %}fa-solid{% else %}fa-regular{% endif %} fa-xl" style="color: {% if pulse.liked %}#d20000{% else %}floralwhite{% endif %}; margin-right: 4px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"></i>
<span class="like-count">{% if pulse.like_count %}{{ pulse.like_count }}{% else %}0{% endif %}</span>
</button>
<button class="share-button" data-pulse-id="{{ pulse.id }}" style="background-color:transparent;color:white;border:none;">
<i class="fa-solid fa-share fa-xl" style="color:floralwhite;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"></i>
<span class="share-count" data-pulse-id="{{ pulse.id }}">{% if pulse.share_count %}{{ pulse.share_count }}{% else %}0{% endif %} </span>
</button>
<button class="comments-button" data-pulse-id="{{ pulse.id }}" style="background-color:transparent;color:white;border:none;">
<i class="fa-solid fa-comments fa-xl toggle-comments" style="color:floralwhite;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"></i>
<span class="comments_count" data-pulse-id="{{ pulse.id }}">{% if pulse.comments %}{{ pulse.comments_count }}{% else %}0{% endif %} </span>
</button>
<button id="global-sound-toggle"><i class="fa-solid fa-volume-xmark" style="color:floralwhite;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"></i></button>
</div>
</div>
<div class="data_artist">
<div class="all_artist">
<div class="artist-content">
<div class="profile_picture_pulse">
{% if pulse.user.profile_picture %}
<img src="{{ pulse.user.profile_picture.url }}" class="img-fluid rounded-circle" style="min-width: 50px;max-width: 50px; height: 50px;" alt="Profile Picture">
{% else %}
<img src='/static/images/default_profile.png' class="img-fluid rounded-circle" style="width: 50px; height: 50px;" alt="Profile Picture">
{% endif %}
</div>
<div class="username_pulse">
<strong> <p id="superstrong" style="margin-bottom:0;">{{ pulse.user.username }} </p></strong>
{% if request.user != pulse.user %}
<button id="sub_pulse"
class="follow-toggle-btn btn-style-2 {% if is_followed %}btn-yes{% else %}btn-no{% endif %}"
data-user-id="{{ pulse.user.id }}"
>
{% if is_followed %}Unfollow{% else %}Follow{% endif %}
</button>
<span style="margin-left:5px;" class="follower-count">{{ pulse.follower_count }}</span>
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
{% endif %}
<button class="toggle-description" aria-label="Show description">
<i class="fa-solid fa-chevron-down"></i>
</button>
</div>
</div>
<div class="description-content">
<p class="description-text">
{{ pulse.description }}<span class="more-text">{{ pulse.description|slice:"100:" }}</span>
{% for hashtag in pulse.hashtags.all %}
<a href="" alt="{{hashtag.name}}"style="text-decoration:none;">#{{hashtag}} </a>
{% endfor %}
</p>
</div>
</div>
<div class="song-content">
<div class="song_pulse">
<img src="/static/images/explore.webp" alt="Cover" class="square-image-x-fill beat-icon-beat_detail">
</div>
</div>
</div>
</div>`
</code>
<code>{% load static %} <script src="{% static 'js/new_pulse.js' %}"></script> <div class="pulse_item"> <div class="video-wrapper"> <video data-src="{{ pulse.video.url }}" class="pulse-video" src="{{ pulse.video.url }}" muted playsinline></video> </div> <div class="comments-section" style="display: none;"> <div class="comment-list"> <h5 class="title_comments">Comments</h5> {% if pulse.comments.all %} {% for comment in pulse.comments.all %} <div class="comment"> <strong>{{ comment.user.username }}:</strong> <p>{{ comment.text }}</p> <small style="color:grey;">{{ comment.created_at|date:"d M Y, H:i" }}</small> </div> {% endfor %} {% else %} <p style="color:white;">Aucun commentaire</p> {% endif %} </div> <textarea class="comment-input" placeholder="Écrivez un commentaire..."></textarea> <button class="button-up" data-pulse-id="{{ pulse.id }}">Envoyer</button> </div> <div class="interacts"> <div class="item-orga"> <button class="like-button" data-pulse-id="{{ pulse.id }}" style="background-color:transparent;color:white;border:none;"> <i class="fa-heart {% if pulse.liked %}fa-solid{% else %}fa-regular{% endif %} fa-xl" style="color: {% if pulse.liked %}#d20000{% else %}floralwhite{% endif %}; margin-right: 4px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"></i> <span class="like-count">{% if pulse.like_count %}{{ pulse.like_count }}{% else %}0{% endif %}</span> </button> <button class="share-button" data-pulse-id="{{ pulse.id }}" style="background-color:transparent;color:white;border:none;"> <i class="fa-solid fa-share fa-xl" style="color:floralwhite;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"></i> <span class="share-count" data-pulse-id="{{ pulse.id }}">{% if pulse.share_count %}{{ pulse.share_count }}{% else %}0{% endif %} </span> </button> <button class="comments-button" data-pulse-id="{{ pulse.id }}" style="background-color:transparent;color:white;border:none;"> <i class="fa-solid fa-comments fa-xl toggle-comments" style="color:floralwhite;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"></i> <span class="comments_count" data-pulse-id="{{ pulse.id }}">{% if pulse.comments %}{{ pulse.comments_count }}{% else %}0{% endif %} </span> </button> <button id="global-sound-toggle"><i class="fa-solid fa-volume-xmark" style="color:floralwhite;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"></i></button> </div> </div> <div class="data_artist"> <div class="all_artist"> <div class="artist-content"> <div class="profile_picture_pulse"> {% if pulse.user.profile_picture %} <img src="{{ pulse.user.profile_picture.url }}" class="img-fluid rounded-circle" style="min-width: 50px;max-width: 50px; height: 50px;" alt="Profile Picture"> {% else %} <img src='/static/images/default_profile.png' class="img-fluid rounded-circle" style="width: 50px; height: 50px;" alt="Profile Picture"> {% endif %} </div> <div class="username_pulse"> <strong> <p id="superstrong" style="margin-bottom:0;">{{ pulse.user.username }} </p></strong> {% if request.user != pulse.user %} <button id="sub_pulse" class="follow-toggle-btn btn-style-2 {% if is_followed %}btn-yes{% else %}btn-no{% endif %}" data-user-id="{{ pulse.user.id }}" > {% if is_followed %}Unfollow{% else %}Follow{% endif %} </button> <span style="margin-left:5px;" class="follower-count">{{ pulse.follower_count }}</span> <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}"> {% endif %} <button class="toggle-description" aria-label="Show description"> <i class="fa-solid fa-chevron-down"></i> </button> </div> </div> <div class="description-content"> <p class="description-text"> {{ pulse.description }}<span class="more-text">{{ pulse.description|slice:"100:" }}</span> {% for hashtag in pulse.hashtags.all %} <a href="" alt="{{hashtag.name}}"style="text-decoration:none;">#{{hashtag}} </a> {% endfor %} </p> </div> </div> <div class="song-content"> <div class="song_pulse"> <img src="/static/images/explore.webp" alt="Cover" class="square-image-x-fill beat-icon-beat_detail"> </div> </div> </div> </div>` </code>
{% load static %}
<script src="{% static 'js/new_pulse.js' %}"></script>
<div class="pulse_item">
    <div class="video-wrapper">
        <video data-src="{{ pulse.video.url }}" class="pulse-video" src="{{ pulse.video.url }}"   muted playsinline></video>
        
    </div>
    <div class="comments-section" style="display: none;">
        <div class="comment-list">
            <h5 class="title_comments">Comments</h5>
            {% if pulse.comments.all %}
                {% for comment in pulse.comments.all %}
                    <div class="comment">
                        <strong>{{ comment.user.username }}:</strong>
                        <p>{{ comment.text }}</p>
                        <small style="color:grey;">{{ comment.created_at|date:"d M Y, H:i" }}</small>
                    </div>
                {% endfor %}
            {% else %}
                <p style="color:white;">Aucun commentaire</p>
            {% endif %}
         </div>
        <textarea class="comment-input" placeholder="Écrivez un commentaire..."></textarea>
        <button class="button-up" data-pulse-id="{{ pulse.id }}">Envoyer</button>
        
    </div>
    <div class="interacts">
        <div class="item-orga">
            
            <button class="like-button" data-pulse-id="{{ pulse.id }}" style="background-color:transparent;color:white;border:none;">
                <i class="fa-heart {% if pulse.liked %}fa-solid{% else %}fa-regular{% endif %} fa-xl" style="color: {% if pulse.liked %}#d20000{% else %}floralwhite{% endif %}; margin-right: 4px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"></i>
                <span class="like-count">{% if pulse.like_count %}{{ pulse.like_count }}{% else %}0{% endif %}</span>
            </button>
            <button class="share-button" data-pulse-id="{{ pulse.id }}" style="background-color:transparent;color:white;border:none;">
                <i class="fa-solid fa-share fa-xl" style="color:floralwhite;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"></i>
                <span class="share-count" data-pulse-id="{{ pulse.id }}">{% if pulse.share_count %}{{ pulse.share_count }}{% else %}0{% endif %} </span>
            </button>
            <button class="comments-button" data-pulse-id="{{ pulse.id }}" style="background-color:transparent;color:white;border:none;">
            <i class="fa-solid fa-comments fa-xl toggle-comments" style="color:floralwhite;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"></i>
            <span class="comments_count" data-pulse-id="{{ pulse.id }}">{% if pulse.comments %}{{ pulse.comments_count }}{% else %}0{% endif %} </span>
            </button>
            <button id="global-sound-toggle"><i class="fa-solid fa-volume-xmark" style="color:floralwhite;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"></i></button>
        </div>
    </div>
    
    <div class="data_artist">
        <div class="all_artist">
            <div class="artist-content">
                <div class="profile_picture_pulse">
                    {% if pulse.user.profile_picture %}
                        <img src="{{ pulse.user.profile_picture.url }}" class="img-fluid rounded-circle" style="min-width: 50px;max-width: 50px; height: 50px;" alt="Profile Picture">
                    {% else %}
                        <img src='/static/images/default_profile.png' class="img-fluid rounded-circle" style="width: 50px; height: 50px;" alt="Profile Picture">
                    {% endif %}
                </div>
                <div class="username_pulse">
                    <strong> <p id="superstrong" style="margin-bottom:0;">{{ pulse.user.username }} </p></strong>
                    
                    {% if request.user != pulse.user %}
                        <button id="sub_pulse"
                        class="follow-toggle-btn btn-style-2 {% if is_followed %}btn-yes{% else %}btn-no{% endif %}"
                            data-user-id="{{ pulse.user.id }}"
                        >
                            {% if is_followed %}Unfollow{% else %}Follow{% endif %}
                        </button>
                        <span style="margin-left:5px;" class="follower-count">{{ pulse.follower_count }}</span>
                        <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
                    {% endif %}
                    
                    <button class="toggle-description" aria-label="Show description">
                        <i class="fa-solid fa-chevron-down"></i>
                    </button>
                </div>
            </div>
            
            
            
            
            
            <div class="description-content">
                <p class="description-text">
                    {{ pulse.description }}<span class="more-text">{{ pulse.description|slice:"100:" }}</span>
                    {% for hashtag in pulse.hashtags.all %}
                    <a href="" alt="{{hashtag.name}}"style="text-decoration:none;">#{{hashtag}} </a>
                    {% endfor %}
                </p>
                
            </div>
        </div>
   

        
        <div class="song-content">
            <div class="song_pulse">
                <img src="/static/images/explore.webp" alt="Cover" class="square-image-x-fill beat-icon-beat_detail">
            </div>
        </div>
    </div>
    
</div>`

New contributor

SKorfa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

You should call initializeNewElements after the new content is loaded and appended to the DOM. You can do this in the loadMoreContent function, after the new content is received and appended to the pulseContainer.

Here’s how you can modify your loadMoreContent function to call initializeNewElements after new content is loaded:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>function loadMoreContent() {
console.log('Trying to load more content...');
if (loading) return;
loading = true;
const url = `/pulses/load-more-pulses/?page=${currentPage}`;
fetch(url)
.then(response => {
console.log('Response status:', response.status);
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
console.log('Data received:', data);
if (data.pulse_data) {
data.pulse_data.forEach(pulse => {
pulseContainer.insertAdjacentHTML('beforeend',
pulse.html);
});
currentPage++;
initializeNewElements(); // Call initializeNewElements
after new content is loaded
}
})
.catch(error => {
console.error('Error loading more content:', error);
})
.finally(() => {
loading = false;
});
}
</code>
<code>function loadMoreContent() { console.log('Trying to load more content...'); if (loading) return; loading = true; const url = `/pulses/load-more-pulses/?page=${currentPage}`; fetch(url) .then(response => { console.log('Response status:', response.status); if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then(data => { console.log('Data received:', data); if (data.pulse_data) { data.pulse_data.forEach(pulse => { pulseContainer.insertAdjacentHTML('beforeend', pulse.html); }); currentPage++; initializeNewElements(); // Call initializeNewElements after new content is loaded } }) .catch(error => { console.error('Error loading more content:', error); }) .finally(() => { loading = false; }); } </code>
function loadMoreContent() {
    console.log('Trying to load more content...');
    if (loading) return;
    loading = true;

    const url = `/pulses/load-more-pulses/?page=${currentPage}`;
    fetch(url)
        .then(response => {
            console.log('Response status:', response.status);
            if (!response.ok) {
                throw new Error('Network response was not ok');
            }
            return response.json();
        })
        .then(data => {
            console.log('Data received:', data);
            if (data.pulse_data) {
                data.pulse_data.forEach(pulse => {
                    pulseContainer.insertAdjacentHTML('beforeend', 
pulse.html);
                });
                currentPage++;
                initializeNewElements(); // Call initializeNewElements 
after new content is loaded
            }
        })
        .catch(error => {
            console.error('Error loading more content:', error);
        })
        .finally(() => {
            loading = false;
        });
}

Additionally, you should also observe the new video elements in the initializeNewElements function. You’re already doing this, but you should also add event listeners for the new video elements. Here’s how you can modify your initializeNewElements function to add event listeners for the new video elements:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>function initializeNewElements() {
const videos = document.querySelectorAll('.pulse-video');
if (!videos.length) return; // Vérification de la présence de vidéos
videos.forEach(video => {
observer.observe(video); // Observe the new video elements
video.addEventListener('error', (e) => {
console.error('Erreur de chargement de la vidéo:', e);
});
video.src = video.getAttribute('data-src');
video.load();
});
setupInteractionButtons(); // Ajouter les interactions aux nouveaux
boutons
setupVideoClickHandler(); // Add event listeners for the new video
elements
}
</code>
<code>function initializeNewElements() { const videos = document.querySelectorAll('.pulse-video'); if (!videos.length) return; // Vérification de la présence de vidéos videos.forEach(video => { observer.observe(video); // Observe the new video elements video.addEventListener('error', (e) => { console.error('Erreur de chargement de la vidéo:', e); }); video.src = video.getAttribute('data-src'); video.load(); }); setupInteractionButtons(); // Ajouter les interactions aux nouveaux boutons setupVideoClickHandler(); // Add event listeners for the new video elements } </code>
function initializeNewElements() {
const videos = document.querySelectorAll('.pulse-video');
if (!videos.length) return; // Vérification de la présence de vidéos

videos.forEach(video => {
    observer.observe(video); // Observe the new video elements
    video.addEventListener('error', (e) => {
        console.error('Erreur de chargement de la vidéo:', e);
    });
    video.src = video.getAttribute('data-src');
    video.load();
});

 setupInteractionButtons(); // Ajouter les interactions aux nouveaux 
 boutons
 setupVideoClickHandler(); // Add event listeners for the new video 
 elements
}

New contributor

Hussnain Iftikhar is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật