Demonstrating reactivity: updating an array property based on a window event

One example scenario involves setting specific elements to have an active class by assigning the property "active" as true (using v-bind:class). This property is modified within a foreach loop, after certain conditions are met, through the method "handleScroll".

Everything works fine when I directly call "handleScroll" in the 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>

However, if I trigger "handleScroll" from inside a window event listener, the reactivity is lost.

Swapping out:

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

for

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

may execute the method but causes reactivity issues with the template.

Inquiry: What is the correct approach to updating these properties in a global window event and then applying them back to the view?

Answer №1

It appears to be a potential issue with Vue reactivity.

To resolve this, consider creating a deep copy of the object by using JSON.parse(JSON.stringify())

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

Answer №2

For updating the value in Vue, consider using Vue.set according to the guidance provided in the caveats section. Here is an example:

Vue.set(sidebarItems[index], 'active', true)

Alternatively, you can also use this approach:

Vue.set(sidebarItems, index, { ...sidebarItems[index], { active: true})

Answer №3

Based on the code provided, there doesn't seem to be any obvious reason why this wouldn't work. Vue's reactivity warning typically applies to adding or removing items from an array, not changing attributes.

To troubleshoot, I recommend double-checking that the method is actually being executed by using console.log:

this.sidebarItems.forEach((sidebarItem: SidebarItem, index) => {
  if (index == 1) {
    sidebarItem.active = true;
    console.log('on: ' + sidebarItem)
  } else {
    sidebarItem.active = false;
    console.log('off: ' + sidebarItem)
  }
});

If this approach doesn't solve your issue, try replicating the problem in jsfiddle. This will likely help pinpoint the root cause. If you're still stuck, feel free to share the fiddle here for further assistance.

Answer №4

In order to see changes reflected, you will need to employ a computed property or a function that is directly called from Vue. The following code snippet demonstrates how this can be achieved -

<template>
  <div class="c-sidebar">
    <p
      v-for="(sidebarItem, index) in sidebarItems"
      :key="index"
      :class="getActiveClass(index)"
    >
      {{ 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
      }
    ];
}

  public getActiveClass(index: number) {
    return index === 1 ? 'active': '';
  }
}
</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it possible to iterate over nested arrays in Vue?

Seeking advice on how to effectively loop through a JSON object like the one provided below using v-for. My goal is to iterate over all ID's/Numbers and the items within each number, then display them in a list format... I'm aware that I can easi ...

Creating dynamic class fields when ngOnInit() is called in Angular

I am trying to dynamically create variables in a class to store values and use them in ngModel and other places. I understand that I can assign values to variables in the ngOnInit() function like this: export class Component implements OnInit{ name: st ...

What is the reason for a type narrowing check on a class property failing when it is assigned to an aliased variable?

Is there a way to restrict the type of property of a class in an aliased conditional expression? Short: I am trying to perform a type narrowing check within a class method, like this._end === null && this._head === null, but I need to assign the r ...

The issue in Vue JS arises when trying to access JSON key values from an object array using v-for

I am currently working on parsing a list of objects found within a JSON payload into a table utilizing Vue.js. My goal is to extract the keys from the initial object in the array and use them as headings for the table. While the code I have in place succe ...

The functionality of GetStaticProps with Typescript is only operational when defined as an arrow function, rather than a function

The documentation for GetStaticProps in NextJs explains it as a function declaration. When trying to add types to it, the following code snippet results: export async function getStaticProps(): GetStaticProps { const db = await openDB(); const fa ...

Tips for triggering a keyboard event to the parent in Vue 3

In my Vue 3 project, I have components nested five levels deep. The top-level component named TopCom and the bottom-level component called MostInnerCom both contain a @keydown event handler. If MostInnerCom is in focus and a key is pressed that it cannot ...

Nuxt3 encountered a request error for an unhandled 500 fetch failure at the http://localhost:3000/__nuxt_vite_node__/manifest url

Can you help me understand this error? https://i.stack.imgur.com/0FGa4.png Without making any adjustments to my code, the app builds successfully. However, when running it on dev mode, the following error appears: npm run dev I have attempted rebuilding ...

Troubleshooting issues with using Laravel's history mode in conjunction with VueJS

Looking to create a seamless web single-page app using Laravel and VueJS but without the annoying "#" in the URL that appears when visiting a new page. Currently, I have: const router = new VueRouter({ mode: 'history', history: false ... ...

Angular Validators.pattern() does not seem to function properly, despite yielding successful results in online regex testers

I have developed a regex pattern on Regex101.com and thoroughly tested it. However, when I applied it to my FormControl Validators.pattern method, it is exhibiting unexpected behavior. This regex pattern is meant for validating the Width input of a packag ...

Eliminate all citation markers in the final compiled result

Currently, I am consolidating all my .ts files into a single file using the following command: tsc -out app.js app.ts --removeComments This is based on the instructions provided in the npm documentation. However, even after compilation, all reference tag ...

Is there a method in TypeScript to make an enum more dynamic by parameterizing it?

I've defined this enum in our codebase. enum EventDesc { EVENT1 = 'event 1', EVENT2 = 'event 2', EVENT3 = 'event 3' } The backend has EVENT1, EVENT2, EVENT3 as event types. On the UI, we display event 1, event 2, a ...

Upon transitioning from typescript to javascript

I attempted to clarify my confusion about TypeScript, but I'm still struggling to explain it well. From my understanding, TypeScript is a strict syntactical superset of JavaScript that enhances our code by allowing us to use different types to define ...

What is the proper way to declare and utilize a constant list within a component template in NuxtJs?

Can someone help me with using itemList in a template? The itemlist is a static list, but I am unsure of where to declare it and how to export it to the template. <template> <table class="table table is-striped is-narrow is-fullwidth" ...

Using Vue's interpolation within the src attribute of my image tag: "{{ image }}"

I am attempting to pass an image url dynamically to my Vue application, but it doesn't seem to be working. I'm starting to question if this is even achievable in Vue / Vuetify. Please confirm if this functionality is possible. <v-img class=& ...

Is it necessary to use Generics in order for a TypeScript `extends` conditional type statement to function properly?

Looking to improve my understanding of the extends keyword in TypeScript and its various uses. I recently discovered two built-in utilities, Extract and Exclude, which utilize both extends and Conditional Typing. /** * Exclude from T those types that are ...

What makes TS unsafe when using unary arithmetic operations, while remaining safe in binary operations?

When it comes to arithmetic, there is a certain truth that holds: if 'a' is any positive real number, then: -a = a*(-1) The Typescript compiler appears to have trouble reproducing arithmetic rules in a type-safe manner. For example: (I) Workin ...

Encountering a 404 error when using Vue history mode in conjunction with an Express

I'm facing an issue with my Vue SPA hosted on an Express server. Whenever I use history mode and refresh the page, I encounter a 404 not found exception. I attempted to solve this problem by utilizing the connect-history-api-fallback package but unfor ...

Is it possible to run NestJS commands without relying on npx?

I recently installed nestjs using npm, but I encountered an issue where it would not work unless I added npx before every nest command. For example: npx nest -v Without using npx, the commands would not execute properly. In addition, I also faced errors ...

An issue has arisen regarding the type definition for the random-string module

I am currently working on creating a .d.ts file for random-string. Here is the code I have so far: declare module "random-string" { export function randomString(opts?: Object): string; } When I try to import the module using: import randomString = ...

"Exploring the power of D3, TypeScript, and Angular 2

I am facing challenges incorporating D3 v4 with Angular 2 (Typescript). While exploring D3 v4, I have referred to several solutions on StackOverflow without success. I have imported most of the necessary D3 libraries and typings (utilizing TS 2.0) and adde ...