Use VueJS v-on:click and Vanilla JS to collapse various divs when clicked

Can VueJS and vanilla JS be used to collapse specific divs among many?

I have information contained in separate card elements that include a title and a body. My goal is to make the body of each card expand or collapse when the respective title is clicked.

I am currently utilizing VueJS and prefer to avoid incorporating JQuery for now, focusing on pure JavaScript instead.

You can view an example of what I mean by checking out this example. Please note that I acknowledge the issue with using the same ID for multiple elements - it was simply done quickly for demonstration purposes.

<div class="section">
    <div class="title" @click="toggle"><span class="toggleIcon" id="toggleIcon">{{toggleIcon}}</span>Toggle This Section</div>
    <hr/>
    <div class="body" id="toggle">
        <img style="height:100px" src="https://cdn.vox-cdn.com/thumbor/Pkmq1nm3skO0-j693JTMd7RL0Zk=/0x0:2012x1341/1200x800/filters:focal(0x0:2012x1341)/cdn.vox-cdn.com/uploads/chorus_image/image/47070706/google2.0.0.jpg">
     </div>
</div>

The challenge I am facing right now is being able to collapse individual divs instead of all at once.

Answer №1

Vue.js operates on data, so any changes in the DOM should mirror changes in the underlying data. To achieve this, it's recommended to encapsulate the cards in a component. This way, each card can keep track of its individual state using a flag like v-show to toggle visibility:

Vue Instance

Vue.component('card', {
  template: '#card',
  methods: {
    toggle() {
     this.showSection = !this.showSection
    }
  },
  data() {
    return {
      showSection: true, // Flag to show section
      imageUrl: 'https://cdn.vox-cdn.com/thumbor/Pkmq1nm3skO0-j693JTMd7RL0Zk=/0x0:2012x1341/1200x800/filters:focal(0x0:2012x1341)/cdn.vox-cdn.com/uploads/chorus_image/image/47070706/google2.0.0.jpg',
      toggleIcon: '+'
    }
  }
})

Markup

  <div class="section">
    <div class="title" v-on:click="toggle">
      <span class="toggleIcon" id="toggleIcon">{{toggleIcon}}</span> Toggle This Section
    </div>
    <hr/>
    <!-- BIND v-show to the showSection data property to reflect changes -->
    <div class="body" v-show="showSection">
      <img v-bind:src="imageUrl">
    </div>
  </div>

By toggling the showSection flag without directly manipulating the DOM, Vue will automatically update the view accordingly.

See the live demo on JSFiddle here: https://jsfiddle.net/craig_h_411/j1wh75v9/1/

Dynamically Passing Content to Cards

To inject different content into each card, you can utilize Vue slots:

<template id="card">
  <div class="section">
    <div class="title" v-on:click="toggle">
      <span class="toggleIcon" id="toggleIcon">{{toggleIcon}}</span> Toggle This Section
    </div>
    <hr/>
    <div class="body" v-show="showSection">
      <!-- Add slot details here -->
      <slot></slot>
    </div>
  </div>
</template>

With slots, content between the component tags gets inserted where the slot tags are defined in the component. For example:

<card>I'm a card</card>
<card> I'm another card</card>

The text provided between the card tags will be placed within the designated slot. Keep in mind that data properties accessed within slots must be available in the parent scope, not the component's scope.

Check out the interactive example on JSFiddle: https://jsfiddle.net/craig_h_411/ew1epg61/

Answer №2

Here is a different approach to the collapsible card design, featuring slots and inspired by @craig_h:

<template>
  <div class="section">
    <div :class="[isActive ? 'active' : '', 'collapsible']" v-on:click="toggle">
      Click Here to Toggle This Section <span class="toggleIcon" id="toggleIcon">{{ toggleIcon }}</span>
    </div>
    <div :class="[isActive ? 'block' : 'none', 'content']" v-show="isActive">
      <slot></slot>
    </div>
  </div>
</template>

<script>
export default {
  name: 'CollapsableCard',
  components: {},
  data() {
    return {
      isActive: false,
      toggleIcon: '+',
    }
  },
  methods: {
    toggle() {
      this.isActive = !this.isActive
    },
  },
}
</script>

<style scoped>
.collapsible {
  background-color: #d8f8ea;
  color: black;
  cursor: pointer;
  padding: 18px;
  width: 100%;
  border: none;
  text-align: left;
  outline: none;
}

.content {
  padding: 0 18px;
  overflow: hidden;
  background-color: #eefcf6;
}
</style>

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

Dynamic Code for Removing List Items Based on Date

I need assistance in resolving an issue with my company's website design and function. Specifically, I am working on a page that displays a list of events where employees will be present throughout the year. Here is an example: <div class="contai ...

What is the best way to ensure the initial item in an accordion group remains open by default when using NextJS?

I've successfully developed an accordion feature in NextJS from scratch and it's functioning flawlessly. However, I am looking to have the first item of the accordion open automatically when the page loads. Can anyone guide me on how to make this ...

Adding a class to the body for a specific route in web development

I'm facing a situation where there is a class named: product-page-bottom-padding The requirement is to apply this class only to the /product/{slug} route for the body element. It should not be present in any other routes. Can you suggest how to mana ...

What sets apart .ejs from .html files?

In my Node Js project, all front end files are in .ejs format and call the server.js for backend work. 1) Is there additional functionality provided by ejs compared to html? 2) Does this pertain to expressJs functionality in Node? 3) Can I use angularJs ...

I am currently working on an Electron Project and am interested in incorporating vueJS into it

I'm working on an Electron Project and I'm unable to incorporate vuejs into it. Can someone guide me on how to use vuejs in an Electron Project? Do I need to install vue cli and electron separately? ...

Obtain the current date using Moment JS in JavaScript

Here is a scenario with code : let currentTime = moment(); console.log(currentTime.format()); // 2019-11-25T20:23:50+02:00 console.log(currentTime.toDate()); // 2019-11-25T18:23:50.916Z After applying the timezone change on Heroku using the command ...

Sending an image dynamically as a prop to a child component

Within my parent component, I retrieve an object from an API which I later enhance with an image as a key/value pair. Subsequently, I pass this modified object to a child component for rendering. In order to accomplish this, I referred to the following pos ...

Applying a variety of elements to a single function

I am in the process of creating a mini-survey and I want the buttons to change color when clicked, but return to normal when another button is selected within the same question. Currently, clicking on a button turns it red while leaving the others clear. H ...

Await the reply from Angular while using Selenium WebDriver

I am currently automating an Angular-based application using Selenium WebDriver (Java). After selecting an option from a dropdown in the Application Under Test (AUT), data is loaded onto the page through an AJAX call to a web service. However, there is no ...

Modifying webpack settings for a create-react-app based project: A step-by-step guide

After starting a new react project with create-react-app, I am looking to update the webpack configuration. However, I cannot seem to locate the webpack file. Should I be creating this file myself, or is there another process involved? As someone who is ...

How come React-Native isn't displaying successfully retrieved data using Axios?

I recently installed axios using the command below: npm i axios After writing the code below, I encountered an issue where React-Native doesn't display any data or throw any errors: import React, {useState, useEffect} from 'react'; import a ...

Can a simultaneous read/write conflict occur in JavaScript while browsing?

A situation has arisen where I am executing multiple (let's say four) AJAX calls using AngularJS http get, and I desire each call to invoke a callback function that increments a counter. This way, I can track when all four threads have finished. I am ...

What is the method for retrieving the name of an object's property within an Angular template

I am trying to display the name of a nested object's property using Angular interpolation <ng-container ngFor="let item of saleDetailsAggegater.productMap | keyvalue"> <tr *ngFor="let qtyMap of item.value | keyvalue"&g ...

Switch between clicking and hiding

I am currently working on data tables and have successfully loaded my table via ajax, which also populates a new row drop down. However, I am experiencing an issue where I can get the row to drop down but cannot get it to close again. It simply adds the ...

Insert information into a dialog box in Vuetify

I am currently exploring Vuetify and working on creating a user interface that displays a table of discovered Wifi networks along with each network's properties. Users should have the ability to edit the stored password or remove a Wifi network from t ...

Add a script tag to every image in my HTML at once using C#

Managing a site with a thousand images can be overwhelming, especially when trying to add a script tag like <%=Settings.MyDomain%> to each one. I'm looking for a more efficient way to accomplish this task without spending hours on manual labor. ...

The functionality of resizing a layout in Html5/CSS3 is not functioning correctly

Whenever I resize the window, I am looking to have A B C displayed one after the other in a vertical sequence, I have been struggling with this for quite some time. Can someone please help me figure out how to achieve this? Thank you! A B C div#me ...

How can I ensure a DIV is shown on every sub-page?

Is there a way to dynamically display a <div id="chatbox"> in all subpages without needing to manually edit each one? For example, adding this code to the main index.html file and having it appear on /products/index.html. ...

Adjust the size of the font based on the screen resolution

What is the best way to adjust font size based on screen resolution so that text remains as a single line when the screen is small? For example: http://prntscr.com/2qa9ze <div class="centerbreaking"> <section id="breaking-news"> <div id ...

Connect a responsive div to a main div

I'm relatively new to the world of Javascript, CSS, and HTML. Currently, I'm attempting to anchor a div to the center and bottom of its parent div. The parent div contains a responsive background image and my fa fa-arrow icon is correctly positi ...