Categories
Vuetify

Vuetify — Parallax and Color Picker

Vuetify is a popular UI framework for Vue apps.

In this article, we’ll look at how to work with the Vuetify framework.

Parallax Height

We can set the height of the parallax scrolling with the height prop.

For example, we can write:

<template>
  <v-parallax dark src="https://cdn.vuetifyjs.com/images/backgrounds/vbanner.jpg" height="300">
    <v-row align="center" justify="center">
      <v-col class="text-center" cols="12">
        <h1 class="display-1 font-weight-thin mb-4">Hello world</h1>
        <h4 class="subheading">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h4>
      </v-col>
    </v-row>
  </v-parallax>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({}),
};
</script>

Color Pickers

We can add a color picker with the v-color-picker component.

The v-color-picker component uses the v-model props to control the color displayed.

For example, we can write:

<template>
  <v-container>
    <v-row>
      <v-col cols="12" md="4">
        <v-btn v-for="t in types" :key="t" class="my-4" block @click="type = t">{{ t }}</v-btn>
      </v-col>
      <v-col class="d-flex justify-center">
        <v-color-picker v-model="color"></v-color-picker>
      </v-col>
      <v-col cols="12" md="4">
        <v-sheet dark class="pa-4">
          <pre>{{ showColor }}</pre>
        </v-sheet>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    types: ["hex", "hexa", "rgba", "hsla", "hsva"],
    type: "hex",
    hex: "#FF00FF",
    hexa: "#FF00FFFF",
    rgba: { r: 255, g: 0, b: 255, a: 1 },
    hsla: { h: 300, s: 1, l: 0.5, a: 1 },
    hsva: { h: 300, s: 1, v: 1, a: 1 },
  }),
  computed: {
    color: {
      get() {
        return this[this.type];
      },
      set(v) {
        this[this.type] = v;
      },
    },
    showColor() {
      if (typeof this.color === "string") return this.color;

      return JSON.stringify(
        Object.keys(this.color).reduce((color, key) => {
          color[key] = Number(this.color[key].toFixed(2));
          return color;
        }, {}),
        null,
        2
      );
    },
  },
};
</script>

We have the v-color picker component with the v-model to set the color state.

We set the type with the setter in the computed property.

There are different kinds of color pickers.

Picker’s Elevation

We can change the color picker’s elevation with the flat and elevation props:

<template>
  <v-row justify="space-around" align="center">
    <v-color-picker v-model="picker" flat></v-color-picker>

    <v-color-picker v-model="picker" elevation="15"></v-color-picker>
  </v-row>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    picker: null,
  }),
};
</script>

flat makes the color picker flat.

And elevation sets the elevation of the color picker.

Swatches

We can add the show-swatches prop to display an array of color swatches a user can pick from.

For example, we can write:

<template>
  <v-row justify="space-around">
    <v-color-picker class="ma-2" show-swatches></v-color-picker>
    <v-color-picker class="ma-2" :swatches="swatches" show-swatches></v-color-picker>
    <v-color-picker class="ma-2" show-swatches swatches-max-height="300px"></v-color-picker>
  </v-row>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    swatches: null,
  }),
};
</script>

We add the show-swatches prop to show the color swatch.

Conclusion

We can change the parallax container’s height and add color pickers with Vuetify.

Categories
Vuetify

Vuetify — Pagination, and Parallax

Vuetify is a popular UI framework for Vue apps.

In this article, we’ll look at how to work with the Vuetify framework.

Paginations

We can add pagination links with the v-pagination component.

The component is controlled by the v-model directive.

For example, we can write:

<template>
  <div class="text-center">
    <v-container>
      <v-row justify="center">
        <v-col cols="8">
          <v-container class="max-width">
            <v-pagination v-model="page" class="my-4" :length="15"></v-pagination>
          </v-container>
        </v-col>
      </v-row>
    </v-container>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    page: 1,
  }),
};
</script>

to add the pagination links.

The v-pagination component has the length prop to set how many buttons to show.

v-model has the model to get and set the state of the page .

Limit Number of Links

We can set the maximum number of visible pages with the total-visible prop.

For example, we can write:

<template>
  <div class="text-center">
    <v-container>
      <v-row justify="center">
        <v-col cols="8">
          <v-container class="max-width">
            <v-pagination v-model="page" class="my-4" :length="15" :total-visible="8"></v-pagination>
          </v-container>
        </v-col>
      </v-row>
    </v-container>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    page: 1,
  }),
};
</script>

We have the total-visible prop to set the max number of buttons to show.

Circle Buttons

The circle prop turns the buttons into circles.

For example, we can write:

<template>
  <div class="text-center">
    <v-container>
      <v-row justify="center">
        <v-col cols="8">
          <v-pagination v-model="page" :length="5" circle></v-pagination>
        </v-col>
      </v-row>
    </v-container>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    page: 1,
  }),
};
</script>

to make the buttons circles.

Icons

The prev-icon and next-icon props let us change the previous and next button icons:

<template>
  <div class="text-center">
    <v-pagination v-model="page" :length="4" prev-icon="mdi-menu-left" next-icon="mdi-menu-right"></v-pagination>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    page: 1,
  }),
};
</script>

Disabled

We can disable pagination buttons with the disabled prop:

<template>
  <div class="text-center">
    <v-pagination :length="3" disabled></v-pagination>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    page: 1,
  }),
};
</script>

Parallax

The v-parallax component lets us create a 3D effect that makes an image appear to scroll slower than the window.

For example, we can use it by writing:

<template>
  <v-parallax dark src="https://cdn.vuetifyjs.com/images/backgrounds/vbanner.jpg">
    <v-row align="center" justify="center">
      <v-col class="text-center" cols="12">
        <h1 class="display-1 font-weight-thin mb-4">Hello world</h1>
        <h4 class="subheading">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h4>
      </v-col>
    </v-row>
  </v-parallax>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    page: 1,
  }),
};
</script>

It takes the src prop to set the URL of the background image.

The default slot has the foreground content.

Conclusion

We have the v-pagination component to add the pagination buttons.

And we have the v-parallax component to add a parallax scrolling effect.

Categories
Vuetify

Vuetify — Overlays

Vuetify is a popular UI framework for Vue apps.

In this article, we’ll look at how to work with the Vuetify framework.

Overlays

We can add overlays with the v-overlay component.

It’s used to provide emphasis on particular elements or parts of it.

And it’s useful for signaling state change.

We can create one by writing:

<template>
  <v-row align="center" justify="center">
    <v-card height="300" width="250">
      <v-row justify="center">
        <v-btn color="success" class="mt-12" @click="overlay = !overlay">Show Overlay</v-btn>

        <v-overlay :absolute="absolute" :value="overlay">
          <v-btn color="success" @click="overlay = false">Hide Overlay</v-btn>
        </v-overlay>
      </v-row>
    </v-card>
  </v-row>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    absolute: true,
    overlay: false,
  }),
};
</script>

We have the v-btn component to add a button to show an overlay.

And we have the v-overlay component that’s triggered by clicking the button.

The absolute prop makes it positioned with an absolute position.

value lets us set the overlay.

Opacity

We can change the opacity of the v-overlay component.

For example, we can write:

<template>
  <v-row align="center" justify="center">
    <v-card height="300" width="250">
      <v-row justify="center">
        <v-btn color="orange lighten-2" class="mt-12" @click="overlay = !overlay">Show Overlay</v-btn>

        <v-overlay :absolute="absolute" :opacity="opacity" :value="overlay">
          <v-btn color="orange lighten-2" @click="overlay = false">Hide Overlay</v-btn>
        </v-overlay>
      </v-row>
    </v-card>
  </v-row>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    absolute: true,
    opacity: 1,
    overlay: false,
  }),
};
</script>

The opacity prop lets us change the opacity of the v-overlay .

Z Index

The z-index of the overlay can be changed with the z-index prop.

For example, we can write:

<template>
  <v-row justify="center">
    <v-btn class="white--text" color="teal" @click="overlay = !overlay">Show Overlay</v-btn>

    <v-overlay :z-index="zIndex" :value="overlay">
      <v-btn class="white--text" color="teal" @click="overlay = false">Hide Overlay</v-btn>
    </v-overlay>
  </v-row>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    overlay: false,
    zIndex: 0,
  }),
};
</script>

We change the z-index prop to the value we want to place it above other elements.

Loader

The overlay can have a loader icon placed on top of it.

For example, we can write:

<template>
  <div class="text-center">
    <v-btn color="deep-purple accent-4" class="white--text" @click="overlay = !overlay">
      Launch Application
      <v-icon right>mdi-open-in-new</v-icon>
    </v-btn>

    <v-overlay :value="overlay">
      <v-progress-circular indeterminate size="64"></v-progress-circular>
    </v-overlay>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    overlay: false,
  }),

  watch: {
    overlay(val) {
      val &&
        setTimeout(() => {
          this.overlay = false;
        }, 3000);
    },
  },
};
</script>

The v-overlay component has the v-progress-circular component to display the circular progress display.

The overlay watcher sets the this.overlay to false after 3 seconds.

Advanced Overlays

We can have overlays that go over a card.

For example, we can write:

<template>
  <v-hover>
    <template v-slot:default="{ hover }">
      <v-card class="mx-auto" max-width="344">
        <v-img src="https://cdn.vuetifyjs.com/images/cards/forest-art.jpg"></v-img>

        <v-card-text>
          <h2 class="title primary--text">Forests</h2>
          <p>Lorem ipsum</p>
        </v-card-text>

        <v-card-title>
          <v-rating :value="4" dense color="orange" background-color="orange" hover class="mr-2"></v-rating>
          <span class="primary--text subtitle-2">100 Reviews</span>
        </v-card-title>

        <v-fade-transition>
          <v-overlay v-if="hover" absolute color="#036358">
            <v-btn>See more info</v-btn>
          </v-overlay>
        </v-fade-transition>
      </v-card>
    </template>
  </v-hover>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    overlay: false,
  }),
};
</script>

The v-fade-transition adds the transition effect when we display the overlay.

The v-overlay is inside the the v-fade-transition component.

Conclusion

We can add overlays with the v-overlay component with Vuetify.

Categories
JavaScript Best Practices

How to Write Better JavaScript Modules

Like any kind of apps, JavaScript apps also have to be written well.

Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at some best practices we should follow when writing JavaScript modules.

Prefer Named Exports

Named exports have to be imported by the name that the member is exported as.

This is different than default exports which can be imported by any name.

Therefore, named exports are less confusing that default exports.

For example, instead of writing:

export default class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    return `Hello, ${this.name}!`;
  }
}

We write:

export class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    return `Hello, ${this.name}!`;
  }
}

The first example can be imported with any name.

The 2nd has to be imported as Person .

Autocomplete also works with named exports if the text editor we’re using has that feature.

No work during import

We shouldn’t do anything with our exported code.

It’s easy to get unexpected results if we export something with an expression that does work.

For example, the following export is no good:

config.js

export const config = {
  data: JSON.parse(str)
};

The work would still be done after the export is done, so we get the latest value.

When we import it, JSON.parse is called.

This means that the import will be slower.

If we have:

import { config } from 'config';

Then the JSON.parse will be run then.

To make JSON.parse run in a lazy fashion, we can write:

config.js

let parsedData = null;

export const config  = {
  get data() {
    if (parsedData === null) {
      parsedData = JSON.parse(str);
    }
    return parsedData;
  }
};

This way, we cache the parsed string in parsedData .

JSON.parse only runs if parsedData is null .

High Cohesion Modules

Cohesion describes the degree to which components inside a module belong together.

We should make sure that a module belongs together.

This means we should have related entities in one module.

For instance, we can make a math module with functions that do arithmetic operations.

We can write:

math.js

export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export const multiply = (a, b) => a * b;
export const divide = (a, b) => a / b;

All functions do similar things, so they belong in one module.

If we have low cohesion modules, then it’s hard to understand what the module has.

Unrelated things in one module just don’t make sense.

Avoid Long Relative Paths

It’s hard to find a module if they’re nested deeply.

We should avoid deep nesting to avoid long relative paths.

So instead of writing:

import { addDates } from '../../date/add';
import { subtractDates }   from '../../date/subtract';

We write:

import { addDates } from './date/add';
import { subtractDates } from './date/subtract';

If we put them in a Node package, we can use absolute paths:

import { addDates } from 'utils/date/add';
import { subtractDates } from 'utils/date/subtract';

We put everything in a utils package so that we can reference it in an absolute path.

Conclusion

We should make cohesive modules to make understanding them easier.

Also, named exports are better than default ones.

We should export code that does work during export since they’ll run when we import it.

Categories
JavaScript Best Practices

Better JavaScript — State, and Array vs Array-Like Objects

Like any kind of apps, JavaScript apps also have to be written well.

Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at ways to improve our JavaScript code.

No Unnecessary State

APIs can be classified as stateful or stateless.

A stateless API provides functions or methods whose behavior depends on inputs.

They don’t change the state of the program.

If we change the state of a program, then the code is harder to trace.

A part of a program that changes the state is a stateful API.

Stateless APIs are easier to learn and use, more self-documenting, and less error-prone.

They’re also easier to test.

This is because we get some output when we pass in some input.

This doesn’t change because of the external state.

We can create stateless APIs with pure functions.

Pure functions return some output when given some input.

When the inputs are the same in 2 different calls, we get the same output each time.

So instead of writing:

c.font = "14px";
c.textAlign = "center";
c.fillText("hello, world!", 75, 25);

We write:

c.fillText("14px", "center", "hello, world!", 75, 25);

The 2nd case is a function that takes inputs and doesn’t depend on the font and textAlign property as it does in the previous example.

Stateless APIs are also more concise.

Stateful APIs led to a proliferation of additional statements to set the internal state of an object.

Use Structural Typing for Flexible Interfaces

JavaScript objects are flexible, so we can just create object literals to create interfaces with items we want to expose to the public.

For instance, we can write:

const book = {
  getTitle() {
    /* ... */
  },
  getAuthor() {
    /* ... */
  },
  toHTML() {
    /* ... */
  }
}

We have some methods that we want to expose to the public.

We just provide this object as an interface for anything that uses our library.

This is the easiest way to create APIs that the outside world can use.

Distinguish Between Array and Array-Like Objects

JavaScript has arrays and array-like objects.

They aren’t the same.

Arrays have their own methods and can store data in sequence.

They’re also an instance of the Array constructor.

Array-like objects don’t have array methods.

To check if something is an array, we call the Array.isArray method to check.

If it return false , then it’s not an array.

Array-like objects can be iterable or not.

If they’re iterable, then we can convert them to an array with the spread operator.

For instance, we can convert NodeLists and the arguments object to an array:

[...document.querySelectorAll('div')]
[...arguments]

We convert the NodeList and the arguments object to an array.

If it’s a non-iterable array-like object, which is one with non-negative integer keys and a length property, we can use the Array.from method to do the conversion.

For instance, we can write:

const arr = Array.from({
  0: 'foo',
  1: 'bar',
  length: 2
})

Then arr would be:

["foo", "bar"]

Conclusion

We shouldn’t have unnecessary states in our program.

Also, duck typing is good for identifying types.

And we should distinguish between array and array-like objects.