I’m using Vue2 and I face some problems with dynamic class binding (highlight in the navigation menubar the current section name in which the user is currently). I’m using the Intersection observerAPI which I initialize and let it loop over my components from the mounted() life hook. However, when I update the current section in my observer:
if (active.length) { this.activeEntry = active[0].target.childNodes[0].id console.log(this.activeEntry) }
(For full code see below) it prints the changes of the current sections “targetEntry” to the console, but… my actual data “targetEntry” doesn’t actually get updated/affected (Am I not able to change data from inside the observer?). I guess I mixe here some things up. How do I need to rewrite my observer functionality (i.e. make use of computed) to actually change my “targetEntry” data so the dynamic classes binding will be executed? I’m still a beginner to Vue and Javascript…
Many thanks in advance!
<template> <div id="Navigation-c"> <ul> <li :class="{ active: activeEntry == 'Entry-c' }" v-scroll-to="'#Entry-c'"><font-awesome-icon icon="fa-solid fa-chevron-up" /></li> <li :class="{ active: activeEntry == 'Motivation-c' }" v-scroll-to="'#Motivation-c'"><p>Intro</p></li> <li :class="{ active: activeEntry == 'NeuralNetworks-c' }" v-scroll-to="'#NeuralNetworks-c'"><p>AI</p></li> <li :class="{ active: activeEntry == 'About-c' }" v-scroll-to="'#About-c'"><p>About</p></li> <li :class="{ active: activeEntry == 'Contact-c' }" v-scroll-to="'#Contact-c'"><p>Contact</p></li> </ul> </div> </template> <script> export default { name: "Navigation-c", data: () => ({ activeEntry: '', observer: null }), methods: { }, updated() { }, mounted() { this.observer = new IntersectionObserver( function (entries) { const active = entries.filter((e) => e.isIntersecting); if (active.length) { this.activeEntry = active[0].target.childNodes[0].id console.log(this.activeEntry) } }, { threshold: [0.5] } ) // loop over components const matches = document.querySelectorAll("section.box"); for (let i = 0; i < matches.length; i++) { this.observer.observe(matches[i]); } }, computed: { }, created() { }, }; </script> <style lang="scss" scoped> .active { color: red !important; } </style>
Advertisement
Answer
The keyword this
loses it’s context inside of new IntersectionObserver()
without the use of an arrow function. Therefore attempting to assign this.activeEntry
will not work unless you rewrite using the arrow function:
mounted() { this.observer = new IntersectionObserver( (entries) => { // arrow function! const active = entries.filter((e) => e.isIntersecting); if (active.length) { this.activeEntry = active[0].target.childNodes[0].id console.log(this.activeEntry) } }, { threshold: [0.5] } ) // loop over components const matches = document.querySelectorAll("section.box"); for (let i = 0; i < matches.length; i++) { this.observer.observe(matches[i]); } },