Categories
Quasar

Developing Vue Apps with the Quasar Library — More Flexbox Properties

Quasar is a popular Vue UI library for developing good looking Vue apps.

In this article, we’ll take a look at how to create Vue apps with the Quasar UI library.

Align Self

We can use the self-* classes to add the align-self CSS property into our child elements.

Horizontal Alignment

We can use the justify-* classes to horizontally align child elements.

For example, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>

  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <div class="row justify-center">
        <div class="col-4">
          1
        </div>
        <div class="col-4">
          2
        </div>
      </div>
    </div>

    <script>
      new Vue({
        el: "#q-app",
        data() {
          return {};
        },
        methods: {}
      });
    </script>
  </body>
</html>

We add the justify-center class to center the child divs.

Also, we can add justify-start to align the child divs on the left.

justify-end align the child divs on the right.

justify-around spaces the child divs with even spacing in between them.

And justify-between spaces the child divs with space between them.

Column Wrapping

Columns will wrap to the next row automatically if the width exceeds 12 columns.

For example, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>

  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <div class="row">
        <div class="col-6 col-sm-3">.col-6 .col-sm-3</div>
        <div class="col-6 col-sm-3">.col-6 .col-sm-3</div>
        <div class="col-6 col-sm-3">.col-6 .col-sm-3</div>
        <div class="col-6 col-sm-3">.col-6 .col-sm-3</div>
      </div>
    </div>

    <script>
      new Vue({
        el: "#q-app",
        data() {
          return {};
        },
        methods: {}
      });
    </script>
  </body>
</html>

We have col-6 to make the div 6 columns wide if the screen hits the xs breakpoint.

col-sm-3 makes the div 3 columns if the screen hits the sm breakpoint or higher.

Offsetting Columns

We can use the offset-* classes to move divs by a given number of columns.

For instance, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="[https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons](https://medium.com/r/?url=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto%3A100%2C300%2C400%2C500%2C700%2C900%7CMaterial%2BIcons)"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>

  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <div class="row">
        <div class="col-md-4">.col-md-4</div>
        <div class="col-md-4 offset-md-4">.col-md-4 .offset-md-4</div>
      </div>
    </div>

    <script>
      new Vue({
        el: "#q-app",
        data() {
          return {};
        },
        methods: {}
      });
    </script>
  </body>
</html>

We have offset-md-4 to shift the div 4 columns to the right if the screen hits the md breakpoint or wider.

Nesting

Also, we can nest flexbox rows and columns.

For instance, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>

  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <div class="row">
        <div class="col-sm-9">
          <p>Level 1</p>
          <div class="row">
            <div class="col-8 col-sm-6">
              Level 2
            </div>
            <div class="col-4 col-sm-6">
              Level 2
            </div>
          </div>
        </div>
      </div>
    </div>

    <script>
      new Vue({
        el: "#q-app",
        data() {
          return {};
        },
        methods: {}
      });
    </script>
  </body>
</html>

to nest a row inside another column.

Conclusion

We can apply various flexbox CSS properties with the classes provided by Quasar.

Categories
Quasar

Developing Vue Apps with the Quasar Library — Breakpoints and Flexbox

Quasar is a popular Vue UI library for developing good looking Vue apps.

In this article, we’ll take a look at how to create Vue apps with the Quasar UI library.

Breakpoints

Quasar uses the following breakpoints:

  • xs — Up to 599px
  • sm — Up to 1023px
  • md — Up to 1439px
  • lg — Up to 1919px
  • xl — Bigger than 1920px

Flexbox

Quasar comes with flexbox helper classes.

We can create rows with the row class and columns with the col class.

For example, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>

  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <div class="row">
        <div class="col">
          .col
        </div>
        <div class="col">
          .col
        </div>
      </div>
    </div>

    <script>
      new Vue({
        el: "#q-app",
        data() {
          return {};
        },
        methods: {}
      });
    </script>
  </body>
</html>

The col class will divide the rows into equal-sized columns.

Setting One Column Width

We can specify the column width of a column.

For instance, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>

  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <div class="row">
        <div class="col">
          .col
        </div>
        <div class="col-6">
          .col-6
        </div>
        <div class="col">
          .col
        </div>
      </div>
    </div>

    <script>
      new Vue({
        el: "#q-app",
        data() {
          return {};
        },
        methods: {}
      });
    </script>
  </body>
</html>

We set the middle column’s class to col-6 to make it wider.

The max-width of a column is 12 units.

Variable Width Content

We can add variable-width content with Quasar.

For instance, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>

  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <div class="row">
        <div class="col-12 col-md-2">
          .col-12 .col-md-2
        </div>
        <div class="col-12 col-md-auto">
          .col-12 .col-md-auto
        </div>
        <div class="col-12 col-md-2">
          .col-12 .col-md-2
        </div>
      </div>
    </div>

    <script>
      new Vue({
        el: "#q-app",
        data() {
          return {};
        },
        methods: {}
      });
    </script>
  </body>
</html>

We have col-md-2 to make the column width 2 when the breakpoint is md .

col-md-auto makes the width automatically sized.

Alignment

We can change the alignment of the elements in the flexbox container with the classes provided by Quasar.

For example, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>

  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <div class="row items-start">
        <div class="col">
          1
        </div>
        <div class="col">
          2
        </div>
        <div class="col">
          3
        </div>
      </div>
    </div>

    <script>
      new Vue({
        el: "#q-app",
        data() {
          return {};
        },
        methods: {}
      });
    </script>
  </body>
</html>

We have the items-start class to put all the column divs at the top of the container.

There’s also the items-center class to make the child elements vertically centered and items-end makes the child elements align to the bottom.

Conclusion

We can use the classes provided by Quasar to position and size our elements.

Categories
Quasar

Getting Started with Developing Vue Apps with the Quasar Library

Quasar is a popular Vue UI library for developing good looking Vue apps.

In this article, we’ll take a look at how to create Vue apps with the Quasar UI library.

Getting Started

The easiest way to get started is with the UMD build of the framework.

We can use that with only a script tag.

To do this, we write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>

  <body>
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>

    <script>
      new Vue({
        el: "#q-app",
        data() {
          return {};
        },
        methods: {}
      });
    </script>
  </body>
</html>

to create an empty Quasar app.

We add the CSS for Google fonts and Quasar in the head tag.

Then we add Vue and Quasar in the body .

The 3rd script tag is the Vue app instance.

Colors

Quasar comes with its own colors.

For example, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>

  <body>
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-btn color="red">button</q-btn>
    </div>

    <script>
      new Vue({
        el: "#q-app",
        data() {
          return {};
        },
        methods: {}
      });
    </script>
  </body>
</html>

We added the q-btn with the color prop set to red to make the background color red.

It comes with many other colors.

Spacing

Quasar has spacing helper classes.

For instance, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>

  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-card class="q-mt-md q-mr-sm">hello world</q-card>
    </div>

    <script>
      new Vue({
        el: "#q-app",
        data() {
          return {};
        },
        methods: {}
      });
    </script>
  </body>
</html>

The q-mt-md and q-mr-sm are the classes for adding the top and right margins respectively.

md is the medium screen size and sm is the small screen breakpoint.

CSS Shadows

We can apply shadows to our components with the provided classes.

For example, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>

  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-card class="shadow-2">hello world</q-card>
    </div>

    <script>
      new Vue({
        el: "#q-app",
        data() {
          return {};
        },
        methods: {}
      });
    </script>
  </body>
</html>

We set the shadow-2 class to add a shadow with a depth of 2 around the card.

Other classes include:

  • no-shadow — remove any shadow
  • inset-shadow — set an inset shadow
  • shadow-N — where N is an integer from 1 to 24.
  • shadow-transition — apply a CSS transition on the shadow

We can also have shadows pointing up with:

  • shadow-up-1 — set a depth of 1
  • shadow-up-2 — set a depth of 2
  • shadow-up-N — where N is an integer from 1 to 24.

They will apply a shadow on the top of the component.

Conclusion

We can get started with Quasar with the UMD module, which can be included with a script tag.

Categories
Vue 3

Form Validation in a Vue 3 App with Vee-Validate 4 — Cross-Field Validation and Array Validations

Form validation is an important part of any app.

In this article, we’ll look at how to use Vee-Validate 4 in our Vue 3 app for form validation.

Cross-Field Validation with defineRules

We can add cross-field validation without the Yup library.

To do this, we write:

<template>
  <div>
    <Form @submit="onSubmit">
      <div>
        <label for="password">Password</label>
        <Field name="password" type="password" rules="required|min:5" />
        <ErrorMessage name="password" />
      </div>

      <div>
        <label for="passwordConfirmation">Confirm Password </label>
        <Field
          name="passwordConfirmation"
          type="password"
          rules="required|confirmed:@password"
        />
        <ErrorMessage name="passwordConfirmation" />
      </div>
      <button type="submit">Submit</button>
    </Form>
  </div>
</template>

<script>
import { Field, Form, ErrorMessage, defineRule } from "vee-validate";

defineRule("required", (value) => {
  if (!value) {
    return "This is required";
  }
  return true;
});

defineRule("min", (value, [min]) => {
  if (value && value.length < min) {
    return `Should be at least ${min} characters`;
  }
  return true;
});

defineRule("confirmed", (value, [other]) => {
  if (value !== other) {
    return `Passwords do not match`;
  }
  return true;
});

export default {
  name: "App",
  components: {
    Field,
    Form,
    ErrorMessage,
  },
  methods: {
    onSubmit(values) {
      alert(JSON.stringify(values, null, 2));
    },
  },
};
</script>

We called defineRule to define the required rule to check if the field is filled in.

min checks if the field has a minimum amount of characters.

confirmed checks that the other field’s value matches the current field’s value.

value has the value of the field. And other has the value of the other field.

Array Fields

We can validate fields that are rendered from an array.

To do this, we write:

<template>
  <div>
    <Form @submit="onSubmit" :validation-schema="schema">
      <fieldset v-for="(user, idx) in users" :key="user.id">
        <legend>User {{ idx }}</legend>
        <label :for="`name_${idx}`">Name</label>
        <Field :id="`name_${idx}`" :name="`users[${idx}].name`" />
        <ErrorMessage :name="`users[${idx}].name`" as="p" />

        <label :for="`email_${idx}`">Email</label>
        <Field
          :id="`email_${idx}`"
          :name="`users[${idx}].email`"
          type="email"
        />
        <ErrorMessage :name="`users[${idx}].email`" as="p" />
        <button type="button" @click="remove(user)">X</button>
      </fieldset>

      <button type="button" @click="add">Add User +</button>
      <button type="submit">Submit</button>
    </Form>
  </div>
</template>

<script>
import { Field, Form, ErrorMessage } from "vee-validate";
import * as yup from "yup";

export default {
  name: "App",
  components: {
    Field,
    Form,
    ErrorMessage,
  },
  data: () => {
    const schema = yup.object().shape({
      users: yup
        .array()
        .of(
          yup.object().shape({
            name: yup.string().required().label("Name"),
            email: yup.string().email().required().label("Email"),
          })
        )
        .strict(),
    });

    return {
      schema,
      users: [
        {
          id: Date.now(),
        },
      ],
    };
  },
  methods: {
    onSubmit(values) {
      alert(JSON.stringify(values, null, 2));
    },
    add() {
      this.users.push({
        id: Date.now(),
      });
    },
    remove(item) {
      const index = this.users.indexOf(item);
      if (index === -1) {
        return;
      }

      this.users.splice(index, 1);
    },
  },
};
</script>

We create the schema object with Yup to call yup.array to let us validate array.

Then we call of to let us specify the validation schema for the objects inside.

The name attributes of each field should be a string that takes the form of an array path.

Now when we type in something invalid in any entry, we’ll see errors displayed.

Conclusion

We can do cross-field validation and array field validations in our Vue 3 app with Vee-Validate 4.

Categories
Careers

The Golden Keyword Ratio of SEO

There’re many strategies for selecting topics to blog about, and using the keyword golden ratio is one of them.

In this article, we’ll look at the keyword golden ratio and how to use them to our advantage.

Long-Tail Keywords

If we want to have success in blogging faster, then we have to choose some long-tail keywords.

They’re keywords that aren’t as competitive since they’re longer than the usual popular keywords and therefore, there aren’t as many results competing for rankings by Google.

They are things like “best shaver for men” instead of “best shaver”.

Long-tail keywords have more words in them, so they’re less likely to be in as many articles as shorter keywords.

Keyword Golden Ratio

Doug Cunnington’s keyword golden ratio (KGR) is all about finding those long-tail keywords in a more systematic way.

It lets us get the keywords that are long-tail without us flying blind to find them.

The ratio is the number of alltitle results on Google divided by the search volume.

We can get the search volume of a keyword with keyword tools like the Google Keyword Planner or Keyword Surfer.

For instance, if we want to get the KGR of the keyword “best shaver for men”, we do the following.

First, we find the search volume for “best shaver for men”, which is 7310 according to Keyword Surfer, as we see below:

Then we can get the number of allintitle result searches as follows:

Then the KGR for “best shaver for men” is 3150 / 7310, which 0.43. Any KGR that’s less than 1 is worth targeting with our posts if the search volume is less than 250.

Therefore, since they’re more than 7000 in search volume for “best shaver for men”, we should probably skip it even if the KGR is less than 1 if we following the KGR rule strictly.

The rule is to write posts that target keywords with the following characteristics:

  • less than 250 search volume
  • KGR less than 1, less than 0.25 is even better

We can use KGR as a rough guide or follow it strictly depending on our preferences.

However, since we use a keyword tool, it does give us a better idea of what keywords we should have in our posts.

It also gives us ideas for topics to write about even though we may be running out of ideas.

Keyword tools are great for providing us with ideas and the KGR rules narrow down the set of keywords that we should target.

Conclusion

Using the KGR rule to look for keywords that we want to target in our post is one way to get our keywords ranked easily and to find out what we should write about.

The important takeaway is that we should be targeting keywords that aren’t too competitive.