Categories
Vue

Adding Dropdowns to a Vue App with the Vue Select Package

To make dropdowns easier, we can use the Vue Select plugin to add the dropdown.

It can do much more than the select element.

In this article, we’ll look at how to get started with the package.

Getting Started

We can add the package by installing it by running:

npm install vue-select

or

yarn add vue-select

Then we can use it by registering the component in main.js

import Vue from "vue";
import App from "./App.vue";
import vSelect from "vue-select";
import "vue-select/dist/vue-select.css";

Vue.component("v-select", vSelect);
Vue.config.productionTip = false;

new Vue({
  render: (h) => h(App)
}).$mount("#app");

And then in our component file, we add:

<template>
  <div id="app">
    <v-select :options="['Canada', 'United States']"></v-select>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

The options prop lets us add the options for the dropdown.

We can also populate the select options with an array:

<template>
  <div id="app">
    <v-select :options="options"></v-select>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      options: [
        { label: "Canada", code: "ca" },
        { label: "United States", code: "us" }
      ]
    };
  }
};
</script>

Then label value will be displayed.

We can set the property name with the strings to display.

For example, we can write:

<template>
  <div id="app">
    <v-select label="countryName" :options="options"></v-select>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      options: [
        { countryName: "Canada", code: "ca" },
        { countryName: "United States", code: "us" }
      ]
    };
  }
};
</script>

Null / Empty Options

We can set options to an empty array if we don’t want any options displayed.

Getting and Setting

We can bind the selected value to a state with v-model .

For example, we can write:

<template>
  <div id="app">
    <v-select v-model="selected" :options="options"></v-select>
    {{selected}}
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      selected: "",
      options: ["Canada", "United States"]
    };
  }
};
</script>

selected will automatically be changed to the value selected.

We can also set the value prop if we only want to set the value selected:

<template>
  <div id="app">
    <v-select :value="selected" :options="options"></v-select>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      selected: "Canada",
      options: ["Canada", "United States"]
    };
  }
};
</script>

Returning a Single Key with reduce

We can return a single key with the reduce prop.

For example, if we have:

<template>
  <div id="app">
    <v-select
      v-model="selected"
      :reduce="country => country.code"
      label="countryName"
      :options="options"
    ></v-select>
    {{selected}}
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      selected: "",
      options: [
        { countryName: "Canada", code: "ca" },
        { countryName: "United States", code: "us" }
      ]
    };
  }
};
</script>

Then v-model will be bound to the code value of the selected object with the selected object.

reduce works with deeply nested values.

For example, we can write:

<template>
  <div id="app">
    <v-select
      v-model="selected"
      :reduce="country => country.meta.code"
      label="countryName"
      :options="options"
    ></v-select>
    {{selected}}
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      selected: "",
      options: [
        { countryName: "Canada", meta: { code: "ca" } },
        { countryName: "United States", meta: { code: "us" } }
      ]
    };
  }
};
</script>

The selected value is now bound to the meta.code property of the selected object.

Conclusion

The vue-select package lets us add a lot more functionality to a dropdown than a regular select element.

Categories
Vue

Add Infinite Scrolling to a Vue App with vue-infinite-scroll

Infinite scrolling is where the user can keep scrolling to get new data and append it to the bottom of the page.

In this article, we’ll look at how to add infinite scrolling to a Vue app with the vue-infinite-scroll plugin.

Install

We can install it by running:

npm install vue-infinite-scroll --save

Usage

After installing it, we can use it.

First, we register the plugin in main.js :

import Vue from "vue";
import App from "./App.vue";
import infiniteScroll from "vue-infinite-scroll";
Vue.use(infiniteScroll);
Vue.config.productionTip = false;

new Vue({
  render: (h) => h(App)
}).$mount("#app");

This registers it globally.

We can also register it locally by writing:

import infiniteScroll from 'vue-infinite-scroll'
new Vue({
  directives: {infiniteScroll}
})

Then we can use it bu writing:

<template>
  <div id="app">
    <div v-infinite-scroll="loadMore" infinite-scroll-disabled="busy" infinite-scroll-distance="10">
      <div v-for="n in num" :key="n">
        <img :src="`https://picsum.photos/id/${n}/300/150`">
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      num: 10,
      busy: false
    };
  },
  methods: {
    loadMore() {
      this.busy = true;
      setTimeout(() => {
        this.num += 50;
        this.busy = false;
      }, 1000);
    }
  }
};
</script>

The v-infinite-scroll directive makes the div become an infinite scrolling container.

We set it to the loadMore method so that we move.

infinite-scroll-distance is the distance in percentage relative to the bottom of the screen.

The loadMore method will run we scroll the screen within the distance of the screen.

infinite-scroll-disabled lets us disabling infinite scrolling when some condition is true .

We display infinite scrolling when we’re loading more data.

Conclusion

We can add infinite scrolling to a Vue app with the vue-infinite-scroll plugin.

Categories
Buefy

Buefy — Snackbar and Steppers

Buefy is a UI framework that’s based on Bulma.

In this article, we’ll look at how to use Buefy in our Vue app.

Snackbar

A snackbar is a simple popup component.

We call the this.$buefy.snackbar.open method to open it:

<template>
  <section>
    <button class="button is-medium" @click="snackbar">Launch snackbar</button>
  </section>
</template>

<script>
export default {
  methods: {
    snackbar() {
      this.$buefy.snackbar.open(`snackbar`);
    }
  }
};
</script>

We can add more options to it”

<template>
  <section>
    <button class="button is-medium" @click="snackbar">Launch snackbar</button>
  </section>
</template>

<script>
export default {
  methods: {
    snackbar() {
      this.$buefy.snackbar.open({
        duration: 5000,
        message: "<b>snackbar</b>",
        type: "is-danger",
        position: "is-bottom-left",
        actionText: "Undo",
        queue: false,
        onAction: () => {
          this.$buefy.toast.open({
            message: "Action pressed",
            queue: false
          });
        }
      });
    }
  }
};
</script>

duration sets how long it’s shown in milliseconds.

message sets the message text. It can include HTML.

type sets the color of the snackbar text.

position sets the position.

actionText sets the text of the action.

queue sets whether the snackbar should queue with other notices.

onAction is run when the action text is clicked.

Steps

Buefy comes with a stepper to display the steps that users should take.

For example, we can write:

<template>
  <section>
    <b-steps
      v-model="activeStep"
      :animated="isAnimated"
      :rounded="isRounded"
      :has-navigation="hasNavigation"
      :icon-prev="prevIcon"
      :icon-next="nextIcon"
      :label-position="labelPosition"
      :mobile-mode="mobileMode"
      icon-pack="fa"
    >
      <b-step-item step="1" label="First" :clickable="isStepsClickable">
        <h1 class="title has-text-centered">Account</h1>
      </b-step-item>

      <b-step-item
        step="2"
        label="Second"
        :clickable="isStepsClickable"
        :type="{'is-success': isProfileSuccess}"
      >
        <h1 class="title has-text-centered">Profile</h1>
      </b-step-item>

      <b-step-item step="3" :visible="showSocial" label="Social" :clickable="isStepsClickable">
        <h1 class="title has-text-centered">Social</h1>
      </b-step-item>

      <b-step-item
        :step="showSocial ? '4' : '3'"
        label="Finish"
        :clickable="isStepsClickable"
        disabled
      >
        <h1 class="title has-text-centered">Finish</h1>
      </b-step-item>

      <template v-if="customNavigation" slot="navigation" slot-scope="{previous, next}">
        <b-button
          outlined
          type="is-danger"
          icon-pack="fa"
          icon-left="arrow-circle-left"
          :disabled="previous.disabled"
          @click.prevent="previous.action"
        >Previous</b-button>
        <b-button
          outlined
          type="is-success"
          icon-pack="fa"
          icon-right="arrow-circle-right"
          :disabled="next.disabled"
          @click.prevent="next.action"
        >Next</b-button>
      </template>
    </b-steps>
  </section>
</template>

<script>
export default {
  data() {
    return {
      activeStep: 0,

      showSocial: false,
      isAnimated: true,
      isRounded: true,
      isStepsClickable: false,

      hasNavigation: true,
      customNavigation: false,
      isProfileSuccess: false,

      prevIcon: "arrow-circle-left",
      nextIcon: "arrow-circle-right",
      labelPosition: "bottom",
      mobileMode: "minimalist"
    };
  }
};
</script>

We add the b-steps component to add the steps.

b-step-item has the content that we display below the step number.

icon-prev has the icon for the previous button.

icon-next has the icon for the next button.

animated lets us enable or disable animation.

rounded lets us make the step icon rounded.

icon-pack sets the icon pack to use.

'fa' is for Font Awesome.

has-navigation enables or disables navigation buttons.

The icons are added by the link tag:

<link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
      integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN"
      crossorigin="anonymous"
    />

with the public/index.html.

The navigation slot lets us add our own navigation controls.

previous and next has the methods to let us go forward and backward.

disabled lets us know when to disable the nav buttons.

Conclusion

We can add notifications and steps display with Buefy.

Categories
Buefy

Buefy — Loading Placeholder and Sidebar

Buefy is a UI framework that’s based on Bulma.

In this article, we’ll look at how to use Buefy in our Vue app.

Skeleton Loading Placeholder

Buefy comes with a skeleton component that we can use as a placeholder to show when content is loading.

To add it, we can use the b-skeleton component:

<template>
  <section>
    <b-skeleton width="20%" animated></b-skeleton>
    <b-skeleton width="40%" animated></b-skeleton>
    <b-skeleton width="60%" animated></b-skeleton>
    <b-skeleton width="80%" animated></b-skeleton>
  </section>
</template>

<script>
export default {
  data() {
    return {};
  },
  methods: {}
};
</script>

width has the width of the bar as the percentage of the screen viewport.

animated makes it animated.

Also, we can add a circle placeholder with the circle prop:

<template>
  <section>
    <figure class="media-left">
      <p class="image is-64x64">
        <b-skeleton circle width="64px" height="64px"></b-skeleton>
      </p>
    </figure>
  </section>
</template>

<script>
export default {
  data() {
    return {};
  },
  methods: {}
};
</script>

Sidebar

We can add a sidebar with the b-sidebar component.

For instance, we can write:

<template>
  <section>
    <b-sidebar
      type="is-light"
      :fullheight="fullheight"
      :fullwidth="fullwidth"
      :overlay="overlay"
      :right="right"
      v-model="open"
    >
      <div class="p-1">
        <img src="https://picsum.photos/id/1/100/50" alt="logo">
        <b-menu>
          <b-menu-list label="Menu">
            <b-menu-item label="Info"></b-menu-item>
            <b-menu-item icon="settings">
              <template slot="label" slot-scope="props">Administrator
                <b-icon class="is-pulled-right" :icon="props.expanded ? 'menu-down' : 'menu-up'"></b-icon>
              </template>
              <b-menu-item label="Users"></b-menu-item>
              <b-menu-item>
                <template slot="label">Devices
                  <b-dropdown aria-role="list" class="is-pulled-right" position="is-bottom-left">
                    <b-icon icon="dots-vertical" slot="trigger"></b-icon>
                    <b-dropdown-item>action 1</b-dropdown-item>
                    <b-dropdown-item>action 2</b-dropdown-item>
                  </b-dropdown>
                </template>
              </b-menu-item>
            </b-menu-item>
          </b-menu-list>
          <b-menu-list label="Actions">
            <b-menu-item label="Logout"></b-menu-item>
          </b-menu-list>
        </b-menu>
      </div>
    </b-sidebar>
  </section>
</template>

<script>
export default {
  data() {
    return {
      open: true,
      overlay: true,
      fullheight: true,
      fullwidth: false,
      right: false
    };
  }
};
</script>

<style>
.p-1 {
  padding: 1em;
}
</style>

to add a sidebar with the b-sidebar component.

type sets the color style.

fullHeight makes it full height.

fullWidth makes it full width.

overlay add an overlay below the sidebar.

right makes it display on the right.

v-model controls the open state of the sidebar.

We can make it static with the position prop et to 'static' :

<template>
  <section>
    <b-sidebar
      position="static"
      :fullheight="fullheight"
      :fullwidth="fullwidth"
      :right="right"
      v-model="open"
    >
      <div class="p-1">
        <img src="https://picsum.photos/id/1/100/50" alt="logo">
        <b-menu>
          <b-menu-list label="Menu">
            <b-menu-item label="Info"></b-menu-item>
            <b-menu-item icon="settings">
              <template slot="label" slot-scope="props">Administrator
                <b-icon class="is-pulled-right" :icon="props.expanded ? 'menu-down' : 'menu-up'"></b-icon>
              </template>
              <b-menu-item label="Users"></b-menu-item>
              <b-menu-item>
                <template slot="label">Devices
                  <b-dropdown aria-role="list" class="is-pulled-right" position="is-bottom-left">
                    <b-icon icon="dots-vertical" slot="trigger"></b-icon>
                    <b-dropdown-item>action 1</b-dropdown-item>
                    <b-dropdown-item>action 2</b-dropdown-item>
                  </b-dropdown>
                </template>
              </b-menu-item>
            </b-menu-item>
          </b-menu-list>
          <b-menu-list label="Actions">
            <b-menu-item label="Logout"></b-menu-item>
          </b-menu-list>
        </b-menu>
      </div>
    </b-sidebar>
  </section>
</template>

<script>
export default {
  data() {
    return {
      open: true,
      overlay: true,
      fullheight: true,
      fullwidth: false,
      right: false
    };
  }
};
</script>

<style>
.p-1 {
  padding: 1em;
}
</style>

Conclusion

We can add placeholders to show when content is loading and a sidebar with Buefy.

Categories
Vue

Add Photo Tiles to a Vue App with the vue-masonry Plugin

We can add a photo grid easily to a Vue app easily with the vue-masonry plugin.

In this article, we’ll look at how to add photo tiles with it.

Installation

We can install it by running:

npm install vue-masonry --save

or add it with a script tag:

<script src="https://unpkg.com/vue-masonry@0.11.3/dist/vue-masonry-plugin-window.js"></script>

If we install the package, then we register the plugin by writing:

import Vue from "vue";
import App from "./App.vue";
import { VueMasonryPlugin } from "vue-masonry";
Vue.use(VueMasonryPlugin);
Vue.config.productionTip = false;

new Vue({
  render: (h) => h(App)
}).$mount("#app");

in main.js .

If we add the script tag, then we write:

var VueMasonryPlugin = window["vue-masonry-plugin"].VueMasonryPlugin
Vue.use(VueMasonryPlugin)

to register it.

Usage

Once we did that, we write:

<template>
  <div id="app">
    <div v-masonry transition-duration="0.3s" item-selector=".item">
      <div v-masonry-tile class="item" v-for="n in 100" :key="n">
        <img :src="`https://picsum.photos/id/${n}/200/300`">
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

to add the photo grid.

The v-masonry-tile makes the div a tile.

v-masonry makes an element the container for the photo grid.

transition-duration is how long a transition runs.

item-selector has the DOM item selector for the list element.

Other props includes column-width for setting the column width with a number.

origin-left sets the group elements to the right instead of the left if it’s false .

origin-top sets the group elements to the bottom instead of the top if it’s false .

stamp specifies which elements are stamped with the layout.

fit-width sets the width of the container to fit the available number of columns.

stagger sets the duration to stagger the item transition so items transition incrementally one after the other.

For example, we can write:

stagger="0.03s"

to set it.

destroy-detail is the duration in milliseconds to wait before unloading the masonry tiles via masonry.destroy() .

We can also trigger redraw manually with the this.$redrawVueMasonry(‘containerId’) method.

containerId is the ID of the block where we want to trigger the redraw.

Conclusion

We can add a photo masonry grid to a Vue app easily with the vue-masonry package.