typescriptvue.jsvuejs2vue-componentvue-class-components

Reactivity: change property in array, applied on window event


Simple use case: Specific elements should get an active class by setting property "active" to true (v-bind:class). The property "active" is set within a foreach loop, after checking some conditions, within method "handleScroll".

This works, if I call "handleScroll" directly in created lifecycle.

<template>
  <div class="c-sidebar">
    <p
      v-for="(sidebarItem, index) in sidebarItems"
      v-bind:key="index"
      v-bind:class="{ 'active': sidebarItem.active }"
    >
      {{ sidebarItem.label }}
    </p>
  </div>
</template>

<script lang="ts">

import { Component, Vue, Prop } from "vue-property-decorator";
import {SidebarItem, SidebarNavItem} from "../../Interfaces";

@Component
export default class Sidebar extends Vue {
  sidebarItems: SidebarItem[];

  public created() {

    this.sidebarItems = [
      {
        label: "First item",
        active: true
      },
      {
        label: "Second item",
        active: false
      }
    ];

    this.handleScroll();
}

  public handleScroll() {
    this.sidebarItems.forEach((sidebarItem: SidebarItem, index) => {
      if (index == 1) {
        sidebarItem.active = true;
      } else {
        sidebarItem.active = false;
      }
    });
  }
}
</script>

If I call "handleScroll" from within a window event, reactivity gets lost.

Change

public created() {
  ...
  this.handleScroll();
}

to

public created() {
  ...
  window.addEventListener("scroll", this.handleScroll);
}

does not work. The method is executed, but reactivity in template gets lost.

Question: How to I set these properties in a global window event and assign them back to view?


Solution

  • It might be Vue reactivity problem.

    Please try changing object reference by creating a deep copy using JSON.parse(JSON.stringify())

    public handleScroll() {
      this.sidebarItems.forEach((sidebarItem: SidebarItem, index) => {
        if (index == 1) {
          sidebarItem.active = true;
        } else {
          sidebarItem.active = false;
        }
      });
      this.sidebarItems = JSON.parse(JSON.stringify(this.sidebarItems))
    }