Vue.Isotope
Vue.Isotope copied to clipboard
Nuxt.js usage example
Please, add Nuxt.js setup example in the documentation getting started section
plugins/vue-isotope.js
import Vue from 'vue'
import isotope from 'vueisotope'
Vue.component('isotope', isotope)
if using vue-imagesLoaded for images plugins/vue-imagesLoaded.js
import Vue from 'vue'
import imagesLoaded from 'vue-images-loaded'
Vue.directive('images-loaded', imagesLoaded)
nuxt.config.js
plugins: [
{ src: '~/plugins/vue-isotope', ssr: false },
{ src: '~/plugins/vue-imagesLoaded', ssr: false },
],
index.vue
<no-ssr>
<isotope ...
</no-ssr>
why should we specify ssr:false?
@AndrewBogdanovTSS Its to turn off Server side rendering. Looks like this package doesn't support SSR. Most of the alternatives doesn't support this feature either.
@vinkodlak Thanks for the example. I got it to work with Nuxt thanks to your example, but now I'm stuck again when trying to add a filter method...
index.vue
<no-ssr>
<isotope :options="options" :list="list">
<div v-for="(item, index) in items" :key="index" class="list-item">
<h2>{{item.title}}</h2>
</div>
</isotope>
<button @click="filter('something')">filter</button>
</no-ssr>
...
data() {
return {
list: [...],
options: {
itemSelector: '.list-item',
layout: 'fitRows',
},
};
},
methods: {
filter(key) => {
this.filter(key);
},
}
I've tried multiple different methods to try to get this working, I can't seem to figure out how to filter/arrange/sort the isotope once it is created. Could somebody give a simple example for Nuxt?
I wasn't able to make filtering work with Nuxt :-/ I ended up using the regular isotope-layout npm package instead, and got it working right away. But still very interested if anyone has an example with vueisotope.
@Meuss follow all steps that @vinkodlak did and do what I have done in one of my projects like here:
.projects {
.thumbnail {
width: 243px;
height: 149px;
.thumbnail-overlay {
opacity: 0;
background-color: rgba(black, 0.8);
transition: opacity 0.25s ease-in-out;
}
&:hover {
.thumbnail-overlay {
opacity: 1;
}
}
}
}
<template lang="pug">
.container
.row
.col-md-4.py-5
ul.list-unstyled.mb-0
li(v-for="(val, key) in option.getFilterData" ).mb-3
div(
:class="[key === filterOption ? 'text-success' : 'text-white']"
@click="filter(key)",
).cursore-pointer {{ key }}
.col-md-8.d-flex
.m-auto.w-100
no-ssr
isotope(
ref='projects'
:options="option",
:list="projects"
)
div(v-for="(item, index) in projects", :key="index").text-white.thumbnail
div.cursore-pointer.d-block.pos-r.p-1
img(:src="require(`../assets/images/project-thumbnails/${item.thumbnail}`)").w-100
.pin.pin-xy.d-flex.text-white.thumbnail-overlay
.m-auto.fs-16.text-center {{ item.title }}
</template>
<script>
export default {
name: 'SectionProjects',
data() {
return {
filterOption: 'Show All',
option: {
getFilterData: {
'Show All'() {
return true;
},
'Production Housing'(itemElem) {
return itemElem.categories.map(x => x === 'Production Housing').includes(true);
},
'Remodel Design'(itemElem) {
return itemElem.categories.map(x => x === 'Remodel Design').includes(true);
},
'Commercial Buildings'(itemElem) {
return itemElem.categories.map(x => x === 'Commercial Buildings').includes(true);
},
'Land Planning'(itemElem) {
return itemElem.categories.map(x => x === 'Land Planning').includes(true);
},
},
},
projects: [
{
title: 'Natomas Meadows Clubhouse',
thumbnail: 'natomas-meadows-clubhouse.png',
categories: ['Commercial Buildings', 'Land Planning'],
}, {
title: 'Donner Lake Remodel',
thumbnail: 'donner-lake-remodel.png',
categories: ['Remodel Design'],
}, {
title: 'Havenwood',
thumbnail: 'havenwood.png',
categories: ['Production Housing'],
},
],
};
},
methods: {
filter(key) {
if (this.filterOption !== key) {
this.$refs.projects.filter(key);
this.filterOption = key;
}
},
},
};
</script>
Hey @Miaaw , I actually did not register the isotope-layout plugin correctly either. I ended up directly using the package in the page I was using. This is probably bad practice (I'm new to Nuxt), but I got it working easily, something like this:
page.vue:
<template>
<div class="page">
<div class="filters">
<a @click="filterItems('selectorA')">filter A</a>
<a @click="filterItems('selectorB')">filter B</a>
<a @click="filterItems('selectorC')">filter C</a>
</div>
<div class="items">
<no-ssr>
<nuxt-link
v-for="(item, index) in items"
:key="index"
:to="item.url"
class="item"
>
</nuxt-link>
</no-ssr>
</div>
</div>
</template>
<script>
let Isotope;
if (process.browser) {
Isotope = require('isotope-layout');
}
export default {
data() {
return {
items: [],
iso: null,
};
},
created() {
const that = this;
this.$axios
.get('/items')
.then(response => {
const items = response.data;
items.forEach(item => {
that.items.push(item);
});
})
.then(() => {
that.isotope();
})
.catch(error => {
console.warn('❌:', error.message);
});
},
methods: {
isotope() {
this.iso = new Isotope('.items', {
itemSelector: '.item',
layout: 'fitRows',
});
this.iso.layout();
},
filterItems(selector) {
this.iso.arrange({ filter: `${selector}` });
},
},
};
</script>
I hope this helps!
@syed-haroon Thanks for your example. I'm gonna try to get vueisotope running again.
@Meuss follow all steps that @vinkodlak did and do what I have done in one of my projects like here:
.projects { .thumbnail { width: 243px; height: 149px; .thumbnail-overlay { opacity: 0; background-color: rgba(black, 0.8); transition: opacity 0.25s ease-in-out; } &:hover { .thumbnail-overlay { opacity: 1; } } } }
<template lang="pug"> .container .row .col-md-4.py-5 ul.list-unstyled.mb-0 li(v-for="(val, key) in option.getFilterData" ).mb-3 div( :class="[key === filterOption ? 'text-success' : 'text-white']" @click="filter(key)", ).cursore-pointer {{ key }} .col-md-8.d-flex .m-auto.w-100 no-ssr isotope( ref='projects' :options="option", :list="projects" ) div(v-for="(item, index) in projects", :key="index").text-white.thumbnail div.cursore-pointer.d-block.pos-r.p-1 img(:src="require(`../assets/images/project-thumbnails/${item.thumbnail}`)").w-100 .pin.pin-xy.d-flex.text-white.thumbnail-overlay .m-auto.fs-16.text-center {{ item.title }} </template> <script> export default { name: 'SectionProjects', data() { return { filterOption: 'Show All', option: { getFilterData: { 'Show All'() { return true; }, 'Production Housing'(itemElem) { return itemElem.categories.map(x => x === 'Production Housing').includes(true); }, 'Remodel Design'(itemElem) { return itemElem.categories.map(x => x === 'Remodel Design').includes(true); }, 'Commercial Buildings'(itemElem) { return itemElem.categories.map(x => x === 'Commercial Buildings').includes(true); }, 'Land Planning'(itemElem) { return itemElem.categories.map(x => x === 'Land Planning').includes(true); }, }, }, projects: [ { title: 'Natomas Meadows Clubhouse', thumbnail: 'natomas-meadows-clubhouse.png', categories: ['Commercial Buildings', 'Land Planning'], }, { title: 'Donner Lake Remodel', thumbnail: 'donner-lake-remodel.png', categories: ['Remodel Design'], }, { title: 'Havenwood', thumbnail: 'havenwood.png', categories: ['Production Housing'], }, ], }; }, methods: { filter(key) { if (this.filterOption !== key) { this.$refs.projects.filter(key); this.filterOption = key; } }, }, }; </script>
Please help! how to define dynamic function for categories in getFilterData:{ ... } ?
Doesn't work for me
Thanks @vinkodlak https://github.com/David-Desmaisons/Vue.Isotope/issues/48#issuecomment-373832820 and @Meuss https://github.com/David-Desmaisons/Vue.Isotope/issues/48#issuecomment-447966700, your methods works! The @Meuss method has the advantage to be compatible in SSR mode 👍 to be functional, rename the method "created()" by "computed()". An example for who don't succeed: https://codesandbox.io/embed/1o8j26k5l7 :)
Hi, I am also trying to use with Nuxt. I'm trying the basic SPA, not SSR as mentioned elsewhere in this thread. I tried modifying the basic example from the docs, so that it would work with import/export statements. Some of the isotope functionality is working, but I am having issues with the v-model inputs and how the DOM reactivity is updating. If I click on a person cell and enter a new id number in the input field, instead of filtering and resorting by that new id, it is somehow creating a new cell for every keystroke. So for example if a person has an id of 5, if I click on that and enter "55", then it keeps 5 and adds another cell with 55. Likewise, if I have 55 in the field and delete the input value, the previously populated people/id cells remain. I am new to Vue so I'm not sure if I have set up the components correctly, or if there is a bug. I have my modified example here.
Also, I'm not sure if this has to do with the problem, but I was confused by the docs Installation
section saying there was a recommendation for webpack, not sure if I need to incorporate this into the code. I assumed vueisotope would already be configured to use webpack.
yo guys i think it dosent work with nuxt 3 but i am trying to use it with nuxt 3 although its not working could you guys help me
<template>
<div class="p-4 flex flex-col space-y-4">
<div class="button-group-wrap">
<h3 class="text-2xl pb-2">Filter</h3>
<div
id="filters"
class="button-group flex space-x-2 class filter-button-group"
>
<button
@click="gettingvalue"
class="bg-slate-700 text-white p-2 rounded-xl"
data-filter="*"
>
show all
</button>
<button
@click="gettingvalue"
class="bg-slate-700 text-white p-2 rounded-xl"
data-filter=".cms"
>
cms
</button>
<button
@click="gettingvalue"
class="bg-slate-700 text-white p-2 rounded-xl"
data-filter=".markup"
>
markup
</button>
<button
@click="gettingvalue"
class="bg-slate-700 text-white p-2 rounded-xl"
data-filter=".programming"
>
programming
</button>
</div>
<br />
<h3 class="text-2xl pb-2">Sort</h3>
<div id="sorts" class="button-group flex space-x-2 sort-by-button-group">
<button
class="bg-slate-700 text-white p-2 rounded-xl"
data-sort-by="original-order"
>
original order
</button>
<button
class="bg-slate-700 text-white p-2 rounded-xl"
data-sort-by="number"
>
id
</button>
<button
class="bg-slate-700 text-white p-2 rounded-xl"
data-sort-by="name"
>
name
</button>
<button
class="bg-slate-700 text-white p-2 rounded-xl"
data-sort-by="category"
>
category
</button>
</div>
</div>
<div class="box-listin flex flex-wrap gap-2">
<div
class="box-item bg-slate-300 programming"
data-category="programming"
>
<h3 class="item-name">JavaScript</h3>
<h3 class="item-id">12</h3>
<div class="item-category bg-slate-400">Programming</div>
</div>
<div class="box-item bg-slate-300 markup" data-category="markup">
<h3 class="item-name">HTML</h3>
<h3 class="item-id">9</h3>
<div class="item-category">Markup</div>
</div>
<div class="box-item bg-slate-300 cms" data-category="cms">
<h3 class="item-name">HubSpot</h3>
<h3 class="item-id">4</h3>
<div class="item-category">CMS</div>
</div>
<div
class="box-item bg-slate-300 programming"
data-category="programming"
>
<h3 class="item-name">Java</h3>
<h3 class="item-id">25</h3>
<div class="item-category">Programming</div>
</div>
<div class="box-item bg-slate-300 cms" data-category="cms">
<h3 class="item-name">WordPress</h3>
<h3 class="item-id">10</h3>
<div class="item-category">CMS</div>
</div>
<div class="box-item bg-slate-300 markup" data-category="markup">
<h3 class="item-name">XML</h3>
<h3 class="item-id">58</h3>
<div class="item-category">Markup</div>
</div>
<div class="box-item bg-slate-300 cms" data-category="cms">
<h3 class="item-name">Drupal</h3>
<h3 class="item-id">2</h3>
<div class="item-category">CMS</div>
</div>
<div
class="box-item bg-slate-300 programming"
data-category="programming"
>
<h3 class="item-name">C++</h3>
<h3 class="item-id">42</h3>
<div class="item-category">Programming</div>
</div>
<div class="box-item bg-slate-300 markup" data-category="markup">
<h3 class="item-name">HubL</h3>
<h3 class="item-id">{{ test }}</h3>
<div class="item-category">Markup</div>
</div>
</div>
</div>
</template>
<!-- <script setup>
const list = [
{
name: "John",
id: 25,
},
{
name: "Joao",
id: 7,
},
{
name: "Albert",
id: 12,
},
{
name: "Jean",
id: 100,
},
];
</script> -->
<!-- <script>
export default {
crerated() {
this.relayout();
console.log("test");
},
data() {
return {
isotope: null,
test: 212,
};
},
methods: {
relayout() {
let elem = document.querySelector(".box-listin");
this.isotope = new Isotope(elem, {
itemSelector: ".box-item",
layoutMode: "masonry",
getSortData: {
number: "item-is parseint",
name: "item-name",
category: "[data-category]",
},
});
},
},
};
</script> -->
<!-- <script>
export default {
crerated() {
this.relayout();
console.log("test");
},
data() {
return {
options: {
itemSelector: ".list-item",
layout: "fitRows",
},
};
},
methods: {
filter(key) {
this.filter(key);
},
},
};
</script> -->
<!-- <script setup>
// const isotope = ref(null);
// onMounted(() => {
// const elem = document.querySelector(".box-listin");
// isotope.value = new isotope(elem, {
// itemSelector: ".box-item",
// layoutMode: "masonry",
// });
// });
// </script> -->
<style scoped></style>