Categories
Vue

Create a Search Filter with Vue.js

We can create a search filter with Vue.js to let us add search functionality to our app.

In this article, we’ll look at how to add a search filter to our Vue app.

Computed Properties

We can create a computed property that watches reactive properties and return a value derived from them.

For instance, we can write:

<template>
  <div id="app">
    <p>original message: "{{ message }}"</p>
    <p>reversed message: "{{ reversedMessage }}"</p>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      message: "Hello"
    };
  },
  computed: {
    reversedMessage() {
      return this.message
        .split("")
        .reverse()
        .join("");
    }
  }
};
</script>

to create the reversedMessage computed property to reverse the this.message string and return it.

Then we can use it in the template like a regular reactive property.

A computed property function must be synchronous so that it returns a value.

Computed properties are useful because they don’t update until the reactive properties update.

Also, the returned value is cached when they don’t need to update unnecessarily.

This is very handy for creating search filters since the filter only updates when we update the search term.

Creating a Search Filter

We can create a search filter with it by using computed properties.

To do that, we write:

<template>
  <div id="app">
    <input v-model="searchQuery">
    <div v-for="r of resultQuery" :key="r.id">{{r.title}}</div>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      searchQuery: null,
      resources: [
        { id: 1, title: "javascript for dummies" },
        { id: 2, title: "vue for dummies" },
        { id: 3, title: "dos for dummies" },
        { id: 4, title: "windows for dummies" },
        { id: 5, title: "html for dummies" }
      ]
    };
  },
  computed: {
    resultQuery() {
      if (this.searchQuery) {
        return this.resources.filter(item => {
          return this.searchQuery
            .toLowerCase()
            .split(" ")
            .every(v => item.title.toLowerCase().includes(v));
        });
      } else {
        return this.resources;
      }
    }
  }
};
</script>

We have the resources array that has all the array items we can search for.

Also, we have the resultQuery computed property to do the search.

We call filter on this.resources is this.searchQuery isn’t an empty string.

In the filter callback, we split the searchQuery string and check if the title has the parts of the searchQuery string.

Otherwise, we return the this.resources array.

In the template, we have the input box to let us search for the items.

It binds to this.searchQuery , so the resultQuery will be computed.

We loop through the resultQuery array and display so that we display the filtered results.

The key prop is required so that the items displayed properly.

Therefore, when we type something into the input box, we’ll see the filtered results updated automatically.

Conclusion

We can add our own search filter easily with Vue.js computed properties.

Categories
Vue

Add Data Visualization to Our Vue App with the JSCharting-Vue Library

We can use the JSCharting-Vue library to add data visualization to our Vue app.

In this article, we’ll look at how to use the library to add some charts to our app.

Installation

We can install the library by running:

npm i -D jscharting-vue

Usage

Once we installed the library, we can use it by writing:

<template>
  <div id="app">
    <JSCharting :options="options" class="columnChart"></JSCharting>
  </div>
</template>

<script>
import JSCharting from "jscharting-vue";

export default {
  data() {
    return {
      name: "columnChart",
      options: {
        type: "horizontal column",
        series: [
          {
            points: [{ x: "A", y: 50 }, { x: "B", y: 30 }, { x: "C", y: 50 }]
          }
        ]
      }
    };
  },
  components: {
    JSCharting
  }
};
</script>

We import the component and register it.

Then we add the data that we want to display in the options object.

The series array has an object with the points array.

x and y has the x and y coordinates.

We set the chart type with the type property to horizontal column so it’ll be displayed with the x-axis as the vertical axis and y-axis as the horizontal axis.

The name is the class name for the chart container.

So we can use it to change the styles:

<template>
  <div id="app">
    <JSCharting :options="options" class="columnChart"></JSCharting>
  </div>
</template>

<script>
import JSCharting from "jscharting-vue";

export default {
  data() {
    return {
      name: "columnChart",
      options: {
        type: "horizontal column",
        series: [
          {
            points: [{ x: "A", y: 50 }, { x: "B", y: 30 }, { x: "C", y: 50 }]
          }
        ]
      }
    };
  },
  components: {
    JSCharting
  }
};
</script>

<style>
.columnChart {
  height: 300px;
}
</style>

We can also set the className prop to set the container div element for the chart.

The callback prop accepts a function that’s called when the chart finishes rendering.

mutatable is a boolean prop to let us set the chart options by calling chart.options .

Updating Charts

To update our chart, we can update the this.options object:

<template>
  <div id="app">
    <JSCharting :options="options" class="columnChart"></JSCharting>
    <button v-on:click="updateData">Update Data</button>
  </div>
</template>

<script>
import JSCharting from "jscharting-vue";

export default {
  data() {
    return {
      name: "columnChart",
      options: {
        type: "horizontal column",
        series: [
          {
            points: [{ x: "A", y: 50 }, { x: "B", y: 30 }, { x: "C", y: 50 }]
          }
        ]
      }
    };
  },
  methods: {
    updateData() {
      this.options = {
        series: [
          {
            name: "Purchases",
            points: [{ x: "A", y: 100 }, { x: "B", y: 230 }, { x: "C", y: 150 }]
          }
        ]
      };
    }
  },
  components: {
    JSCharting
  }
};
</script>

<style>
.columnChart {
  height: 300px;
}
</style>

We set the series.points property to update the data.

The new data will be rendered automatically.

Also, we can do the update directly on the chart:

<template>
  <div id="app">
    <JSCharting ref="chart" :options="options" class="columnChart"></JSCharting>
    <button v-on:click="updateData">Update Data</button>
  </div>
</template>

<script>
import JSCharting from "jscharting-vue";

export default {
  data() {
    return {
      name: "columnChart",
      options: {
        type: "horizontal column",
        series: [
          {
            name: "Purchases",
            points: [{ x: "A", y: 50 }, { x: "B", y: 30 }, { x: "C", y: 50 }]
          }
        ]
      }
    };
  },
  methods: {
    updateData() {
      const chart = this.$refs.chart.instance;
      if (chart) {
        chart.series("Purchases").options({
          points: [{ x: "A", y: 150 }, { x: "B", y: 130 }, { x: "C", y: 150 }]
        });
      }
    }
  },
  components: {
    JSCharting
  }
};
</script>

<style>
.columnChart {
  height: 300px;
}
</style>

We assign a ref to the JSCharting component.

Then we get the ref in the updateData method.

And then we get the series with the series method.

Then we call the options method to set the points for the chart.

Conclusion

We add data visualization to our Vue app with the JSCharting-Vue library.

Categories
Vue

Add Sparklines to Our Vue App with Vue-Trend

Sparklines are small line charts that we display on our page.

In this article, we’ll look at how to use the Vue-Trend library to add sparklines.

Installation

We can install it by running:

npm i vuetrend

Adding Sparklines

After we installed it, we add our sparkling by writing:

main.js

import Vue from "vue";
import App from "./App.vue";
import Trend from "vuetrend";

Vue.use(Trend);
Vue.config.productionTip = false;

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

App.vue

<template>
  <div id="app">
    <trend
      :data="[0, 2, 5, 9, 5, 10, 3, 5, 0, 0, 1, 8, 2, 9, 0]"
      :gradient="['#6fa8dc', '#42b983', '#2c3e50']"
      auto-draw
      smooth
    ></trend>
  </div>
</template>

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

We register the VueTrend plugin in main.js .

And then we used the trend component that comes with the plugin to render our sparkling.

data has the y-axis values in an array.

gradient has the colors for the gradient in the line.

autoDraw lets the line draw itself on mount.

smooth makes the line smooth by making the peaks rounded.

Props

The trend component lets us set different kinds of props.

gradientDirection lets us set the direction of the gradient.

width sets the width of the line.

height sets the height of the line.

padding has the padding.

radius sets the radius for smoothing the line.

autoDrawDuration sets the duration of the auto-draw animation.

autoDrawEasing sets the auto draw easing function.

max specifies the max value.

min specifies the min value.

Some SVG props include stroke to set the stroke color.

strokeWidth to set the stroke width.

strokeOpacity to create a transparent line.

strokeLinecap and strokeLineJoin controls the edges of the line.

strokeDashoffset controls whether the dashes start.

For example, we can write:

<template>
  <div id="app">
    <trend
      :data="[0, 2, 5, 9, 5, 10, 3, 5, 0, 0, 1, 8, 2, 9, 0]"
      :gradient="['#6fa8dc', '#42b983', '#2c3e50']"
      auto-draw
      smooth
      :width="200"
      :stroke-width="5"
    ></trend>
  </div>
</template>

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

We set the width of the chart with width .

And set the width of the line with stroke-width .

Conclusion

We can use the Vue-Trend library to create sparklines easily in our Vue app.

Categories
Vue

Making Non-Reactive Changes Reactive with Vue.set

If we’re making changes to reactive properties in Vue apps that aren’t picked by Vue automatically, then we need to use the Vue.set method.

In this article, we’ll take a look at reactive and non-reactive changes and how we can use Vue.set with non-reactive changes.

Reactivity

Changes for reactive variables are tracked by defining traversing objects and defining getters and setters for them.

They’re used for tracking dependencies and notify Vue of changes.

Every component has a corresponding watcher instance to watch for property changes.

Each time a dependency setter is triggered, the watcher is notified, and cause the component to re-render.

Objects

Vue can’t detect property addition or deletion.

This is because the getter and setter conversion process requires the property to be present so that Vue can make it reactive.

For example, if we have:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>app</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          a: 1
        }
      });
      app.b = 2;
    </script>
  </body>
</html>

Then the b property won’t be watched automatically.

We can’t add properties to the root level of an already created instance.

But we can add new properties to a nested property with Vue.set .

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>app</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      {{someObject.b}}
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          someObject: {}
        }
      });
      Vue.set(app.someObject, "b", 2);
    </script>
  </body>
</html>

We call Vue.set with the property with the object to add the property to.

Then the property name, and then the value.

We can also use the this.$set method in the Vue instance object itself.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>app</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      {{someObject.b}}
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          someObject: {}
        },
        mounted() {
          this.$set(this.someObject, "b", 2);
        }
      });
    </script>
  </body>
</html>

to do the same thing.

We can also use Object.assign and assign it to the same property to add the property:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>app</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      {{someObject.b}}
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          someObject: {}
        },
        mounted() {
          this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 });
        }
      });
    </script>
  </body>
</html>

Reassignment will also trigger Vue to re-render the component.

Arrays

Vue can’t detect some changes to arrays.

It can’t detect directly setting an item with the index.

And it can’t detect modifying the length of the array.

So these 2 changes aren’t reactive:

vm.items[1] = 'x'
vm.items.length = 2

To make the changes, we can use Vue.set again:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>app</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      {{items[1]}}
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          items: ["foo", "bar"]
        }
      });
      Vue.set(app.items, 1, "qux");
    </script>
  </body>
</html>

We call Vue.set with the array property, index, and the value to set for the index.

We can also use splice :

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>app</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      {{items[1]}}
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          items: ["foo", "bar"]
        }
      });
      app.items.splice(1, 1, "qux");
    </script>
  </body>
</html>

The first argument is the index to change, the 2nd is how many items to change, and the 3rd is the value to change the entry with the given index to.

Also, we can call this.$set in the component instance:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>app</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      {{items[1]}}
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          items: ["foo", "bar"]
        },
        mounted() {
          this.$set(this.items, 1, "qux");
        }
      });
    </script>
  </body>
</html>

this.$set takes the same arguments as Vue.set .

Conclusion

The Vue.set method lets us make non-reactive object and array operations reactive.

Categories
Vue

Storing Session Data with the Vue Session Plugin

Storing session data can be made easier with the Vue Session plugin

In this article, we’ll look at how to use the vue-authenticate plugin to add authentication.

Getting Started

We install the package by running:

npm i vue-session

Then we can register in main.js by writing:

import Vue from "vue";
import App from "./App.vue";
import VueSession from "vue-session";
Vue.use(VueSession);
Vue.config.productionTip = false;

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

Then we can use it by writing:

<template>
  <div>
    <form @submit.prevent="login">
      <input v-model="email" type="text" placeholder="email">
      <input v-model="password" type="password" placeholder="password">
      <br>
      <input type="submit" value="log in">
    </form>
  </div>
</template>

<script>
import axios from "axios";
export default {
  data() {
    return {
      email: "",
      password: ""
    };
  },
  methods: {
    async login() {
      const { email, password } = this;
      const {
        data: { token }
      } = await axios.post(
        "https://ClosedThirdPixels--five-nine.repl.co/auth/login",
        {
          password: password,
          email: email
        }
      );
      this.$session.start();
      this.$session.set("jwt", token);
    }
  }
};
</script>

We created a form to let us log in.

In the login method, we make a POST request with Axios.

Once it succeeds, we call the $session.start method to create the session.

Our back end can be something like:

const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors')

const app = express();
app.use(cors())
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.post('/auth/login', (req, res) => {
  res.json({
    token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
  })
});

app.post('/auth/register', (req, res) => {
  res.json({})
});

app.listen(3000, () => console.log('server started'));

to return the token.

We would return a token only when the username and password are valid.

And then we can populate it with our own key-value pairs.

To get the data from the session, we can use the this.$session.get method.

For example, we can write:

$session.get('jwt')

to get the session data with the jwt key.

To check if the session exists, we call this.$session.exists() .

To remove something with the given key, we call this.$session.remove() .

To clear all the data, we call this.$session.clear() .

this.$session.id() returns the session ID.

this.$session.renew() renews the session.

this.$session.destroy() destroys a session.

So we can write:

<template>
  <div>
    <form @submit.prevent="login">
      <input v-model="email" type="text" placeholder="email">
      <input v-model="password" type="password" placeholder="password">
      <br>
      <input type="submit" value="log in">
      <button type="button" @click="logout">log out</button>
    </form>
  </div>
</template>

<script>
import axios from "axios";
export default {
  data() {
    return {
      email: "",
      password: ""
    };
  },
  methods: {
    async login() {
      const { email, password } = this;
      const {
        data: { token }
      } = await axios.post(
        "https://ClosedThirdPixels--five-nine.repl.co/auth/login",
        {
          password: password,
          email: email
        }
      );
      this.$session.start();
      this.$session.set("jwt", token);
    },
    logout() {
      this.$session.destroy();
    }
  }
};
</script>

to add a logout method to destroy the session with this.session.$destroy() .

Flash

We can use the flash property to save data until we read them without having to start a regular session.

this.$session.flash.set(key, value) sets a flash value.

this.$session.flash.get(key) reads and removes a flash value.

this.$session.flash.remove(key) removes a flash value.

Conclusion

Vue Session is an easy to use library for storing sessions within a Vue app.