David-Desmaisons / Vue.Isotope

:iphone: Vue component for isotope filter & sort magical layouts
MIT License
345 stars 48 forks source link

Nuxt.js usage example #48

Open AndrewBogdanovTSS opened 6 years ago

AndrewBogdanovTSS commented 6 years ago

Please, add Nuxt.js setup example in the documentation getting started section

vinkodlak commented 6 years ago

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>
AndrewBogdanovTSS commented 6 years ago

why should we specify ssr:false?

Nisthar commented 6 years ago

@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.

Meuss commented 5 years ago

@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?

Meuss commented 5 years ago

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.

syed-haroon commented 5 years ago

@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>
Meuss commented 5 years ago

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!

Meuss commented 5 years ago

@syed-haroon Thanks for your example. I'm gonna try to get vueisotope running again.

gothaicenter commented 5 years ago

@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:{ ... } ?

PuxianAlHazred commented 5 years ago

Doesn't work for me

zakarialounes commented 5 years ago

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 :)

Feldbot commented 5 years ago

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.

saleheshon0444 commented 4 months ago

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

saleheshon0444 commented 4 months ago
<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>