A guide on reverting toggled item(s) to their original state

I am currently developing an app that reveals a div when clicked. However, if someone clicks on another button to open a different div, I want the previously opened div to hide automatically. While I have managed to achieve this functionality by manually setting this.movies[index].open = false and

this.movies[index].hideImg = true
, it would become impractical with thousands of entries. This is where the toggle(id) method comes into play.

<template>
  <div v-for="(movie, index) in movies" :key="index" class="movieContainer">
    <div class="center">
      <h3>{{ movie.name }}</h3>
      <p class="duration">{{ movie.duration }}</p>

      <button @click="toggle(movie.id)" class="watchBtn">
        <p v-if="movie.hideImg">►</p>
        <p v-else>▼</p>
      </button>
    </div>
    <div v-if="movie.open">
      <video controls="controls" autoplay name="media">
        <source
          :src="require(`@/assets/movie${index + 1}.mp4`)"
          alt="video"
          type="video/mp4"
          width="500px"
          autoplay
        />
      </video>
    </div>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      movies: [
        {
          name: "Windy Highway",
          duration: "15 seconds",
          hideImg: true,
          open: false,
          id: 1,
          movieStart: "0:00",
          movieMid: "0.08",
          movieEnd: "0:15",
        },
        {
          name: "Sunny Station",
          duration: "32 seconds",
          hideImg: true,
          open: false,
          id: 2,
          movieStart: "0:00",
          movieMid: "0.16",
          movieEnd: "0:32",
        },
        {
          name: "Abstract Material",
          duration: "9 seconds",
          hideImg: true,
          open: false,
          id: 3,
          movieStart: "0:00",
          movieMid: "0.05",
          movieEnd: "0:09",
        },
        {
          name: "Pumpkin Drilling",
          duration: "17 seconds",
          hideImg: true,
          open: false,
          id: 4,
          movieStart: "0:00",
          movieMid: "0.09",
          movieEnd: "0:17",
        },
      ],
    };
  },
  methods: {
    toggle(id) {
      
      for (let i = 0; i < this.movies.length; i++) {
        this.movies[i].open = false;
        this.movies[i].hideImg = true;
      }

      this.movies[id - 1].hideImg = !this.movies[id - 1].hideImg;
      this.movies[id - 1].open = !this.movies[id - 1].open;
      console.log(
        this.movies[id - 1].movieStart,
        "-",
        this.movies[id - 1].movieMid,
        "-",
        this.movies[id - 1].movieEnd
      );
    },
  },
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin: 60px auto 0;
}
.watchBtn {
  background-color: red;
  border-radius: 10px;
  margin-left: 10px;
  height: 20px;
  display: flex;
  align-items: center;
}
.watchBtn:hover {
  background-color: rgb(255, 191, 107);
  cursor: pointer;
}
.movieContainer {
  margin: 5px auto;
  display: flex;
  flex-direction: column;
}
.center {
  margin: 0 auto;
  display: flex;
  align-items: center;
}
.duration {
  margin: 0 5px 0 10px;
}
.movieContainer video {
  width: 500px;
}
</style>

Link to the code on StackBlitz

Answer №1

...
toggle(id) {
  this.movies.forEach(movie => { movie.open = false, movie.hideImg = true })
  this.movies[id - 1].hideImg = false;
  this.movies[id - 1].open = true;
},
...

In addition to the above code, here are some improvements that can be made:

  • Switch from using v-if to v-show, as it's quicker for showing/hiding DOM elements
  • Get rid of the hideImg property and rely solely on a single property called open
  • Keep track of the current state so you can close the currently open item again

Check out StackBlitz for an example

<template>
  <div v-for="(movie, index) in movies" :key="index" class="movieContainer">
    <div class="center">
      {{ movie.name }}
      <button @click="toggle(movie.id)" class="watchBtn">
        <p v-show="!movie.open">►</p>
              👆           👆
        <p v-show="movie.open">▼</p>
              👆          👆
      </button>
    </div>
    <div v-show="movie.open">
      <!-- <video controls="controls" autoplay name="media">
        <source
          :src="require(`@/assets/movie${index + 1}.mp4`)"
          alt="video"
          type="video/mp4"
          width="500px"
        />
      </video> -->
      <h2>Test</h2>
    </div>
  </div>
</template>

<script>
export default {
  name: 'App',
  methods: {
    toggle(id) {
👉    const state = this.movies[id - 1].open;
👉    this.movies.forEach((movie) => (movie.open = false));
👉    this.movies[id - 1].open = !state;
    },
  },
  data() {
    return {
      movies: [
        {
          name: 'Pokemon',
          duration: '1hr 12min',
👉
          open: false,
          id: 1,
        },
        {
          name: 'Digimon',
          duration: '2hr 37min',
👉
          open: false,
          id: 2,
        },
        {
          name: 'Transformers',
          duration: '1hr 51min',
👉
          open: true,
          id: 3,
        },
        {
          name: 'Kiepscy',
          duration: '1hr 51min',
👉
          open: true,
          id: 4,
        },
      ],
    };
  },
};
</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

The pagination in Laravel Vue is causing a validation error due to an invalid prop type check failing

Recently, I delved into working with Nuxt.js and decided to install the Laravel-Vue-Pagination plugin. However, I encountered an error message in my console system that reads: [Vue warn]: Invalid prop: type check failed for prop "data". Expected Object, ...

Is it possible to serialize the entirety of a website's Javascript state, including Closure/Hidden scopes?

My goal is to capture a "snapshot" of a webpage while maintaining its interactive functionality, allowing all Javascript states to be saved and restored. An example scenario where this would be beneficial is when a webpage contains script that utilizes glo ...

Accessing JSON files within a subprocess

I have encountered a situation where I am working with two interconnected Node.js apps. One app is calling another using the child process exec method. Within one of the apps, I am attempting to read JSON files using the following method: function readAs ...

Issue with V-checkbox input-value not triggering correctly on change

Query Example: <query #[`${instanceItemIdKey}`]="{ item }"> <v-checkbox :input="item.content" @modify="$notify('onPermissionUpdate', item)" ></v-checkbox> </query> The information that influ ...

Combining JSON arrays

I have two JSON Arrays provided below: Array 1: [ { id : 1, b: 1}, { id : 2, b: 2}, { id : 3, b: 3}, ] Array 2: [ { id : 1, c: 1}, { id : 3, c: 3}, { id : 4, c: 4} ] In my Node.js code, I am looking to merge both arrays as shown ...

My initial experience with Stored Procedures

I am venturing into a new realm of Stored Procedures and I find myself in need of guidance on how to handle params within a Node model. The database experts have provided me with the following: USE [Some_Dev] GO DECLARE @return_value int, @Au ...

Error in Node.js: The res.send method is undefined

I'm having some issues with my first attempt at creating a simple Counter Strike API bot using nodeJS. The problem lies with the res.send function, as I keep getting an error message saying "res.send is not a function" every time I try to use it. Movi ...

Animate a list to expand and collapse the menu options

Here's the concept I'm aiming to achieve: When "PORTFOLIO" is clicked, smoothly push down everything on the page; New links should fade in smoothly; If "PORTFOLIO" is clicked again, reverse all animations. This is my current code snippet: $( ...

Vertical alignment in material-ui's Grid component is not functioning as expected

I have been working on this code snippet to center a button both vertically and horizontally. However, it seems like the button is not positioned correctly along the vertical axis. Any advice or guidance would be greatly appreciated! Could someone assist ...

How can we deliver pure JS, HTML, and CSS content without relying on static HTML pages?

Looking to create a fast app prototype without using React or Vue? I'd like to avoid simply making an html and js file imported within it. Can npm packages, SCSS be used while programming vanilla Javascript minus a framework? ...

Is the performance impacted by using try / catch instead of the `.catch` observable operator when handling XHR requests?

Recently, I encountered an interesting scenario. While evaluating a new project and reviewing the codebase, I noticed that all HTTP requests within the service files were enclosed in a JavaScript try / catch block instead of utilizing the .catch observable ...

Converting Javascript tools into Typescript

I'm currently in the process of migrating my Ionic1 project to Ionic2, and it's been quite an interesting journey so far! One challenge that I'm facing is how to transfer a lengthy list of utility functions written in JavaScript, like CmToFe ...

Avoid activating jQuery functions based on certain screen widths for menu/navigation system

Recently, I've delved into the world of jQuery and attempted to create a simple menu system. The menu is designed to expand its submenu when hovering over the list item at screen widths larger than 480px, and to expand when clicking on the list item a ...

Understanding the process of linking JavaScript code to a database within the ASP.NET framework

I have been successfully using an ASP.NET application to connect to a SQL Server 2016 database. However, I now have a new task of incorporating Javascript into the code in order to retrieve data from the database and present it to the user. I am aware of t ...

Deleting lines from JSON object using Angular or JavaScript

On my webpage, I have a list where you can add a new line by pressing the "+" button (easy with push), but I'm not sure how to remove lines using the "X" button. https://i.stack.imgur.com/nm06A.png This is the JSON structure: "priceExtra" : [ ...

Update the available choices in one select field based on the choice made in another

I am working on a feature where users can select their country, either USA or Canada. Currently, I have all the American states listed in one dropdown menu. However, I want this dropdown to change to display Canadian provinces when users select Canada. Bel ...

The method subprocess.stdout.on in Node.js does not work as expected

How can I load the result from exec by stream in nodejs/Vuetify.js? In nodejs: const child_process = require('child_process'); _execPull(location){ try{ return child_process.exec('docker pull '+location); }catch(error) ...

Creating dynamic forms in Vue using v-for

I'm currently experimenting with creating dynamic form fields using v-for and vuex. My approach involves nesting a v-for inside another v-for. The process of adding new form fields works smoothly, but I encountered an issue when attempting to delete t ...

"Empower your app with the dynamic combination of Meteor Publish and

Consider the scenario below: In my client application, I have created a complex filter stored in a custom reactive object named currentFilter. The method currentFilter.buildQuery() is used to generate the query object for MongoDB database. Due to the la ...

What could be causing the shake effect on the MUI dialog to not work when clicking away?

I am trying to implement a shake effect when the user clicks outside the MUI dialog to indicate that clicking away is not allowed. However, the code I have so far does not seem to be working as the effect is not being applied. Can someone please help me ...