Categories
Vue

Make HTTP Requests in a Vue App with Axios — Handling Errors and Cancellation

Axios is a popular HTTP client that is used with Vue apps.

In this article, we’ll look at how to make requests with Axios in a Vue app.

Removing Interceptors

We can remove request or response interceptors with the eject method.

For example, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import axios from "axios";
const interceptor = axios.interceptors.response.use(
  config => {
    console.log(config);
    return config;
  },
  error => {
    return Promise.reject(error);
  }
);

export default {
  name: "App",
  async beforeMount() {
    const { data } = await axios({
      method: "get",
      url: "https://jsonplaceholder.typicode.com/posts/1"
    });
    console.log(data);
    axios.interceptors.request.eject(interceptor);
  }
};
</script>

to cal the eject method to remove the interceptor.

Add Interceptor to a Custom Instance of Axios

We can add a request or response interceptor to a custom instance of Axios.

To do that, we write:

<template>
  <div id="app"></div>
</template>
<script>
import axios from "axios";

const instance = axios.create({
  baseURL: "https://jsonplaceholder.typicode.com/posts",
  timeout: 1000,
  headers: { "X-Custom-Header": "foobar" }
});

instance.interceptors.response.use(
  config => {
    console.log(config);
    return config;
  },
  error => {
    return Promise.reject(error);
  }
);

export default {
  name: "App",
  async beforeMount() {
    const { data } = await instance.get("/1");
    console.log(data);
  }
};
</script>

We just call instance.interceptors.response.use to add the interceptor to the Axios instance.

We can replace response with request to add a request interceptor to an instance.

Handling Errors

To handle errors, we can catch them. For instance, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import axios from "axios";

export default {
  name: "App",
  async beforeMount() {
    try {
      const { data } = await axios.get(
        "https://jsonplaceholder.typicode.com/posts/1"
      );
      console.log(data);
    } catch (error) {
      if (error.response) {
        console.log(error.response.data);
        console.log(error.response.status);
        console.log(error.response.headers);
      } else if (error.request) {
        console.log(error.request);
      } else {
        console.log("Error", error.message);
      }
      console.log(error.config);
    }
  }
};
</script>

We can check if the error is from the response or the request with the response and request properties.

The message property has the error message.

The config property has the config.

We can also validate the status with a function. Axios will only resolve if the status is what we want.

For example, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import axios from "axios";

export default {
  name: "App",
  async beforeMount() {
    try {
      const { data } = await axios.get(
        "https://jsonplaceholder.typicode.com/posts/1",
        {
          validateStatus(status) {
            return status < 500;
          }
        }
      );
      console.log(data);
    } catch (error) {
      console.log(error);
    }
  }
};
</script>

to add the validateStatus method to resolve the promise returned by axios.get if the status code is less than 500.

Cancellation

To make a request cancellable, we can use a cancel token.

For example, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import axios from "axios";
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

export default {
  name: "App",
  async beforeMount() {
    try {
      source.cancel("Operation canceled by the user.");
      const { data } = await axios.get(
        "https://jsonplaceholder.typicode.com/posts/1",
        {
          cancelToken: source.token
        }
      );
      console.log(data);
    } catch (thrown) {
      if (axios.isCancel(thrown)) {
        console.log("Request canceled", thrown.message);
      } else {
        // handle error
      }
    }
  }
};
</script>

We call the source.cancel method to cancel the request. The argument is the message to show.

axios.isCancel method lets us check if the request is canceled or not.

thrown.message has the message we passed into the argument.

Conclusion

We can handle errors and make requests cancellable with Axios.

Categories
Vue

Make HTTP Requests in a Vue App with Axios

Axios is a popular HTTP client that is used with Vue apps.

In this article, we’ll look at how to make requests with Axios in a Vue app.

Installation

We can install the package by running:

npm i axios

Also, we can add the library with a script tag. Either we can write:

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

or:

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

Making Requests

To make a request with Axios, we just call the methods that come with the library.

For example, to make a GET request, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import axios from "axios";

export default {
  name: "App",
  async beforeMount() {
    const { data } = await axios.get(
      "https://jsonplaceholder.typicode.com/posts"
    );
    console.log(data);
  }
};
</script>

We pass in the URL to the get method to make a GET request.

To make a POST request, we can use the POST method:

<template>
  <div id="app"></div>
</template>
<script>
import axios from "axios";

export default {
  name: "App",
  async beforeMount() {
    const { data } = await axios.post(
      "https://jsonplaceholder.typicode.com/posts",
      {
        title: "foo",
        body: "bar",
        userId: 1
      }
    );
    console.log(data);
  }
};
</script>

The 2nd argument is the request body.

The axios object can also be called directly to make a request.

To make a GET request, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import axios from "axios";

export default {
  name: "App",
  async beforeMount() {
    const { data } = await axios({
      method: "post",
      url: "https://jsonplaceholder.typicode.com/posts",
      data: {
        title: "foo",
        body: "bar",
        userId: 1
      }
    });
    console.log(data);
  }
};
</script>

We have the method property that sets the request method.

url has the request URL.

data has the request body.

To make a GET request, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import axios from "axios";

export default {
  name: "App",
  async beforeMount() {
    const { data } = await axios({
      method: "get",
      url: "https://jsonplaceholder.typicode.com/posts/1"
    });
    console.log(data);
  }
};
</script>

Axios Instance

We can create our own Axios object with the axios.create method:

<template>
  <div id="app"></div>
</template>
<script>
import axios from "axios";
const instance = axios.create({
  baseURL: "https://jsonplaceholder.typicode.com/posts",
  timeout: 1000,
  headers: { "X-Custom-Header": "foobar" }
});

export default {
  name: "App",
  async beforeMount() {
    const { data } = await instance.get("/1");
    console.log(data);
  }
};
</script>

We set the base URL of the requests with the baseURL property.

Also, we can set the headers, timeout, and other request parameters.

Then we call get with the URL relative to the baseURL and get the data .

Interceptors

We can add interceptors for requests and responses. For example, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import axios from "axios";
axios.interceptors.request.use(
  config => {
    console.log(config);
    return config;
  },
  error => {
    return Promise.reject(error);
  }
);

export default {
  name: "App",
  async beforeMount() {
    const { data } = await axios({
      method: "get",
      url: "https://jsonplaceholder.typicode.com/posts/1"
    });
    console.log(data);
  }
};
</script>

We call axios.interceptors.request.use to call intercept requests.

To intercept responses, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import axios from "axios";
axios.interceptors.response.use(
  config => {
    console.log(config);
    return config;
  },
  error => {
    return Promise.reject(error);
  }
);

export default {
  name: "App",
  async beforeMount() {
    const { data } = await axios({
      method: "get",
      url: "https://jsonplaceholder.typicode.com/posts/1"
    });
    console.log(data);
  }
};
</script>

Conclusion

We can make HTTP requests with Axios in our Vue app.

Categories
Vue

Add Metadata to our Vue App with vue-meta

To add meta tags easily in our Vue app, we can use the vue-meta library.

In this article, we’ll look at how to use the Vue Meta library to let us add meta tags to our Vue app.

Installation

We can install it by running:

yarn add vue-meta

or

npm i vue-meta

Also, we can include the library directly with a script tag.

The dev version can be added by writing:

<script src="https://unpkg.com/vue-meta/dist/vue-meta.js"></script>

and the production version can be added by writing:

<script src="https://unpkg.com/vue-meta/dist/vue-meta.min.js"></script>

Adding the Meta Tags

To add the tags, we have to register the plugin.

To do that, we write:

import Vue from "vue";
import App from "./App.vue";
import VueMeta from "vue-meta";

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

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

in main.js to add the plugin.

We can also add an object with some options as the 2nd argument:

import Vue from "vue";
import App from "./App.vue";
import VueMeta from "vue-meta";

Vue.use(VueMeta, {
  keyName: "metaInfo",
  attribute: "data-vue-meta",
  ssrAttribute: "data-vue-meta-server-rendered",
  tagIDKeyName: "vmid",
  refreshOnceOnNavigation: true
});
Vue.config.productionTip = false;

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

keyName is the name of the component option that has all the information to convert to meta tags and attributes.

attributre is the name of the attribute to let vue-meta know how it should manage and ignore.

ssrAttribute is the name of the attribute that’s added to the html tag to inform vue-meta that the server has generated the meta tag.

tagIDKeyName is the property that tells vue-meta to overwrite an item in a tag list.

refreshOnceOnNavigation pauses update once page navigation starts and resume updates when navigation finishes when it’s true .

It can help improve speed and fix flickering when replacing styles.

Once we have registered the plugin, we can add the metaInfo property to add the meta tags:

<template>
  <div id="app"></div>
</template>

<script>
export default {
  name: "App",
  metaInfo: {
    title: "App Title",
    titleTemplate: "%s | My Awesome Webapp"
  }
};
</script>

The title property adds the title that will be replaced with the placeholder.

This means 'App Title' will replace the %s placeholder to form the text content of the title tag.

We can add the style tag to the head with vue-meta. For example, we can write:

<template>
  <div id="app">
    <div class="loading">loading</div>
  </div>
</template>

<script>
export default {
  name: "App",
  metaInfo: {
    style: [
      {
        vmid: "page-load-overlay",
        innerHTML: `
          body div.loading {
            z-index: 999;
            background-color: yellow;
            opacity: 0.9;
          }
        `
      }
    ]
  },
  data() {
    return {
      cssTexts: []
    };
  },
  mounted() {
    this.cssTexts.push({
      vmid: "page-load-overlay",
      innerHTML: null
    });
  }
};
</script>

We set the style property to an object with the values.

Also, we can load the styles dynamically:

<template>
  <div id="app">
    <div class="loading">loading</div>
  </div>
</template>

<script>
export default {
  name: "App",
  metaInfo() {
    const style = this.cssTexts;
    return { style };
  },
  data() {
    return {
      cssTexts: []
    };
  },
  mounted() {
    this.cssTexts.push({
      vmid: "page-load-overlay",
      innerHTML: `
        body div.loading {
          z-index: 999;
          background-color: yellow;
          opacity: 0.9;
        }
      `
    });
  }
};
</script>

The this.cssTexts.push pushes the style.

Conclusion

We can add metadata to the head tag with the vue-meta library.

Categories
Ant Design Vue

Ant Design Vue — Form Validation and Layout

Ant Design Vue or AntD Vue, is a useful UI framework made for Vue.js.

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

Form Validation Rules

We can set the rules with the rules prop:

<template>
  <a-form :form="form">
    <a-form-item
      :label-col="formItemLayout.labelCol"
      :wrapper-col="formItemLayout.wrapperCol"
      label="Name"
    >
      <a-input
        v-decorator="[
          'username',
          { rules: [{ required: true, message: 'Please input your name' }] },
        ]"
        placeholder="Please input your name"
      />
    </a-form-item>
    <a-form-item
      :label-col="formItemLayout.labelCol"
      :wrapper-col="formItemLayout.wrapperCol"
      label="Nickname"
    >
      <a-input
        v-decorator="[
          'nickname',
          { rules: [{ required: checkNick, message: 'Please input your nickname' }] },
        ]"
        placeholder="Please input your nickname"
      />
    </a-form-item>
    <a-form-item :label-col="formTailLayout.labelCol" :wrapper-col="formTailLayout.wrapperCol">
      <a-checkbox :checked="checkNick" @change="handleChange">Nickname is required</a-checkbox>
    </a-form-item>
    <a-form-item :label-col="formTailLayout.labelCol" :wrapper-col="formTailLayout.wrapperCol">
      <a-button type="primary" @click="check">Check</a-button>
    </a-form-item>
  </a-form>
</template>

<script>
const formItemLayout = {
  labelCol: { span: 4 },
  wrapperCol: { span: 8 }
};
const formTailLayout = {
  labelCol: { span: 4 },
  wrapperCol: { span: 8, offset: 4 }
};
export default {
  data() {
    return {
      checkNick: false,
      formItemLayout,
      formTailLayout,
      form: this.$form.createForm(this, { name: "dynamic_rule" })
    };
  },
  methods: {
    check() {
      this.form.validateFields(err => {
        if (!err) {
          console.info("success");
        }
      });
    },
    handleChange(e) {
      this.checkNick = e.target.checked;
      this.$nextTick(() => {
        this.form.validateFields(["nickname"], { force: true });
      });
    }
  }
};
</script>

We set the required property in the object we added to the rules property to the checkNick reactive property so that we can make the nickname required only when the Nickname is required checkbox is checked.

Inline Form

We can set the layout prop to inline to make the form fields display inline:

<template>
  <a-form layout="inline" :form="form" @submit="handleSubmit">
    <a-form-item :validate-status="userNameError() ? 'error' : ''" :help="userNameError() || ''">
      <a-input
        v-decorator="[
          'userName',
          { rules: [{ required: true, message: 'Please input your username!' }] },
        ]"
        placeholder="Username"
      >
        <a-icon slot="prefix" type="user" style="color:rgba(0,0,0,.25)"/>
      </a-input>
    </a-form-item>
    <a-form-item :validate-status="passwordError() ? 'error' : ''" :help="passwordError() || ''">
      <a-input
        v-decorator="[
          'password',
          { rules: [{ required: true, message: 'Please input your Password!' }] },
        ]"
        type="password"
        placeholder="Password"
      >
        <a-icon slot="prefix" type="lock" style="color:rgba(0,0,0,.25)"/>
      </a-input>
    </a-form-item>
    <a-form-item>
      <a-button
        type="primary"
        html-type="submit"
        :disabled="hasErrors(form.getFieldsError())"
      >Log in</a-button>
    </a-form-item>
  </a-form>
</template>

<script>
function hasErrors(fieldsError) {
  return Object.keys(fieldsError).some(field => fieldsError[field]);
}
export default {
  data() {
    return {
      hasErrors,
      form: this.$form.createForm(this, { name: "horizontal_login" })
    };
  },
  mounted() {
    this.$nextTick(() => {
      this.form.validateFields();
    });
  },
  methods: {
    userNameError() {
      const { getFieldError, isFieldTouched } = this.form;
      return isFieldTouched("userName") && getFieldError("userName");
    },
    passwordError() {
      const { getFieldError, isFieldTouched } = this.form;
      return isFieldTouched("password") && getFieldError("password");
    },
    handleSubmit(e) {
      e.preventDefault();
      this.form.validateFields((err, values) => {
        if (!err) {
          console.log("Received values of form: ", values);
        }
      });
    }
  }
};
</script>

Conclusion

We can add form validation and change the layout with Ant Design Vue.

Categories
Ant Design Vue

Ant Design Vue — Date Picker and Form

Ant Design Vue or AntD Vue, is a useful UI framework made for Vue.js.

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

Extra Footer on the Date Picker

We can add an extra footer on the date picker by populating the renderExtraFooter slot:

<template>
  <div>
    <a-date-picker>
      <template slot="renderExtraFooter">extra footer</template>
    </a-date-picker>
  </div>
</template>

We can do the same with the a-range-picker , a-week-picker , and a-month-picker .

Date Picker Date Format

We can format the date picker’s date format our way with Moment:

<template>
  <div>
    <a-date-picker :default-value="moment('2020/01/01', dateFormat)" :format="dateFormat"/>
    <br>
    <a-date-picker
      :default-value="moment('01/01/2020', dateFormatList[0])"
      :format="dateFormatList"
    />
    <br>
    <a-month-picker :default-value="moment('2020/01', monthFormat)" :format="monthFormat"/>
    <br>
    <a-range-picker
      :default-value="[moment('2020/01/01', dateFormat), moment('2015/01/01', dateFormat)]"
      :format="dateFormat"
    />
  </div>
</template>
<script>
import moment from "moment";
export default {
  data() {
    return {
      dateFormat: "YYYY/MM/DD",
      monthFormat: "YYYY/MM",
      dateFormatList: ["DD/MM/YYYY", "DD/MM/YY"]
    };
  },
  methods: {
    moment
  }
};
</script>

We just set the string of the date format and it’ll be formatted.

Date Picker Size

The date picker size can be changed with the size prop:

<template>
  <div>
    <a-date-picker size="large"/>
    <br>
    <a-month-picker size="large" placeholder="Select Month"/>
    <br>
    <a-range-picker size="large"/>
    <br>
    <a-week-picker size="large" placeholder="Select Week"/>
  </div>
</template>
<script>
export default {};
</script>

Time Picker

We can add a time picker to a a-date-picker and a-range-picker with the show-time prop:

<template>
  <div>
    <a-date-picker show-time placeholder="Select Time" @change="onChange" @ok="onOk"/>
    <br>
    <a-range-picker
      :show-time="{ format: 'HH:mm' }"
      format="YYYY-MM-DD HH:mm"
      :placeholder="['Start Time', 'End Time']"
      @change="onChange"
      @ok="onOk"
    />
  </div>
</template>
<script>
export default {
  methods: {
    onChange(value, dateString) {
      console.log("Selected Time: ", value);
      console.log("Formatted Selected Time: ", dateString);
    },
    onOk(value) {
      console.log("onOk: ", value);
    }
  }
};
</script>

The show-time prop can take an object with the time format.

Form

We can add a simple form with the a-form component:

<template>
  <a-form :form="form" :label-col="{ span: 5 }" :wrapper-col="{ span: 12 }" @submit="handleSubmit">
    <a-form-item label="Note">
      <a-input
        v-decorator="['note', { rules: [{ required: true, message: 'Please input your note!' }] }]"
      />
    </a-form-item>
    <a-form-item label="Gender">
      <a-select
        v-decorator="[
          'gender',
          { rules: [{ required: true, message: 'Please select your gender!' }] },
        ]"
        placeholder="Select a option and change input text above"
        @change="handleSelectChange"
      >
        <a-select-option value="male">male</a-select-option>
        <a-select-option value="female">female</a-select-option>
      </a-select>
    </a-form-item>
    <a-form-item :wrapper-col="{ span: 12, offset: 5 }">
      <a-button type="primary" html-type="submit">Submit</a-button>
    </a-form-item>
  </a-form>
</template>

<script>
export default {
  data() {
    return {
      formLayout: "horizontal",
      form: this.$form.createForm(this, { name: "coordinated" })
    };
  },
  methods: {
    handleSubmit(e) {
      e.preventDefault();
      this.form.validateFields((err, values) => {
        if (!err) {
          console.log(values);
        }
      });
    },
    handleSelectChange(value) {
      this.form.setFieldsValue({
        note: `Hi, ${value === "male" ? "man" : "lady"}!`
      });
    }
  }
};
</script>

We add the a-input to add the input.

The v-decorator has the rules for validation for the field.

The this.form.setFieldsValue method sets the form field value.

The this.form reactive property is created by the this.$form.createForm method.

Conclusion

We can add forms and date pickers with the components provided by Ant Design Vue.