Select only one Item from a list of child components in Vue.js 2

0

My question is as follows.

I have a list of folders which, when you click on one of them, will light up and show your information.

All right up to here, now the problem is that when selecting another folder, the previous one will continue to be illuminated. Here's the example:

link

How can I do to select only one folder at a time?

Edit

I already managed to do it, I added an array with the states of the folders so I could change it from the father and not from the son.

link

Although I solve the problem I do not know if it will be the best solution, I do not know if it would be possible to put the states inside the folder array instead of creating another, but in doing so it does not take the changes.

    
asked by Fer 09.04.2017 в 00:33
source

1 answer

1

You do not necessarily need to keep a folder associated with your state. A more practical option would be to send to all the elements the id of the folder that has been asked to be opened (by $emit ) and make a check to know if the current folder is open to update its CSS class.

Example

In each folder, we put a conditional to see when to add the class open (for example):

<li 
  class="folder"
  :class="{open: this.folder.id === open}"
  @click="openFolder"
>
</li>

When you click on each folder, the id of that folder is sent to the parent:

openFolder() {
  this.$emit('open', this.folder.id);
}

Each folder will have the properties folder and open . The latter represents the id of the folder that has asked to open.

props: {
  open: {
    type: Number,
    required: true,
  },
  folder: {
    type: Object,
    required: true
  },
},

And finally, the parent, upon receiving notification that a folder wants to open, updates its own property folderOpen :

methods: {
  onFolderOpen(id) {
    this.folderOpen = id;
  }
},

which is passed as property to each folder:

<ul class="folders">
  <folder
    v-if="ready"
    v-for="folder in folders"
    :folder="folder"
    :open="folderOpen"
    @open="onFolderOpen"
  />
</ul>

Full code

Vue.component('folder', {
  template: '
    <li 
      class="folder"
      @click="openFolder"
    >
      <i
        class="material-icons"
        v-if="open !== folder.id"
      >
        folder
      </i>
      <i
        class="material-icons"
        v-if="open === folder.id"
      >
        folder_open
      </i>
      <label>{{ folder.name }}</label>
    </li>
  ',
  props: {
    open: {
      type: Number,
      required: true,
    },
    folder: {
      type: Object,
      required: true
    },
  },
  methods: {
    openFolder() {
      this.$emit('open', this.folder.id);
    }
  },
});

const app = new Vue({
  data: () => ({
    folders: [],
    folderOpen: -1,
    ready: false,
  }),
  methods: {
    onFolderOpen(id) {
      this.folderOpen = id;
    }
  },
  created() {
    this.folders = [{
        id: 0,
        name: 'Proyectos',
      },
      {
        id: 1,
        name: 'Trabajo',
      },
      {
        id: 2,
        name: 'Hacking',
      },
      {
        id: 3,
        name: 'StackOverflow'
      },
    ];
    this.ready = true;
  },
});

app.$mount('#app');
ul.folders {
  list-style: none;
}

ul.folders li {
  align-items: center;
  color: #555;
  cursor: pointer;
  display: flex;
  font-family: 'Open Sans', sans-serif;
  font-size: 15px;
  height: 40px;
}

ul.folders li i {
  margin: 0 10px 0 0;
  pointer-events: none;
}

ul.folders li label {
  font-weight: 600;
  pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"/>

<div id="app">
  <ul class="folders">
    <folder v-if="ready" v-for="folder in folders" :folder="folder" :open="folderOpen" @open="onFolderOpen" />
  </ul>
</div>
    
answered by 13.04.2017 / 21:34
source