Categories
JavaScript Vue

Making HTTP Requests in a Vue App with Axios

Most apps need to make HTTP requests to an external server for them to be useful.

Vue.js doesn’t come with its own HTTP client.

However, we can add one ourselves so that we can make requests with it.

One of the best HTTP client libraries is the Axios HTTP client.

To use it, first, we in install it by running:

npm i axios

Then to make requests with it, we can write:

<template>
  <div id="app">{{info}}</div>
</template>

<script>
import axios from "axios";

export default {
  name: "App",
  data() {
    return {
      info: {}
    };
  },
  mounted() {
    axios
      .get("https://api.coindesk.com/v1/bpi/currentprice.json")
      .then(response => (this.info = response.data.bpi));
  }
};
</script>

We make a request to the Conidesk API to get the current prices of Bitcoins.

To make the code shorter, we can write:

<template>
  <div id="app">{{info}}</div>
</template>

<script>
import axios from "axios";

export default {
  name: "App",
  data() {
    return {
      info: {}
    };
  },
  async mounted() {
    const response = await axios.get(
      "https://api.coindesk.com/v1/bpi/currentprice.json"
    );
    this.info = response.data.bpi;
  }
};
</script>

We replaced then with await to make the code shorter.

To deal with errors, we can use try/catch:

<template>
  <div id="app">
    <div v-if="!errored">{{info}}</div>
    <div v-else>error</div>
  </div>
</template>

<script>
import axios from "axios";

export default {
  name: "App",
  data() {
    return {
      info: {},
      errored: false
    };
  },
  async mounted() {
    try {
      const response = await axios.get(
        "https://api.coindesk.com/v1/bpi/currentprice.json"
      );
      this.info = response.data.bpi;
    } catch (error) {
      this.errored = true;
    }
  }
};
</script>

We set this.errored to true in the catch block. This catches the error.

Now we see the price data from the API.

To format the data, we can rewrite our template to display the price.

We can write:

<template>
  <div id="app">
    <div v-if="!errored">
      <p v-for="(value, key) in info" :key="key">{{key}}: {{value.rate}}</p>
    </div>
    <div v-else>error</div>
  </div>
</template>

<script>
import axios from "axios";

export default {
  name: "App",
  data() {
    return {
      info: {},
      errored: false
    };
  },
  async mounted() {
    try {
      const response = await axios.get(
        "https://api.coindesk.com/v1/bpi/currentprice.json"
      );
      this.info = response.data.bpi;
    } catch (error) {
      this.errored = true;
    }
  }
};
</script>

We have the v-for directive to loop through the info object.

The value has the value of a property.

The key has the key, which is the currency code.

We display the code property of the value to display the price.

With Axios, we can make HTTP requests easily within in a Vue.js component.

Categories
JavaScript Vue

Add a Table to a Vue App with Buefy

We can add a table with Buefy with the b-table component.

Basic Table

To populate it with data, we just set the data and columns props.

For example, we write:

<template>
  <div id="app">
    <b-table :data="data" :columns="columns"></b-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      data: [
        { id: 1, firstName: "jane", lastName: "smith" },
        { id: 2, firstName: "joe", lastName: "smith" },
        { id: 3, firstName: "alex", lastName: "green" }
      ],
      columns: [
        {
          field: "id",
          label: "ID",
          width: "40",
          numeric: true
        },
        {
          field: "firstName",
          label: "First Name"
        },
        {
          field: "lastName",
          label: "Last Name"
        }
      ]
    };
  }
};
</script>

This creates a basic table by using the b-table component.

We set the data prop to data, which has an array of objects.

Each property is mapped to the column by specifying the objects in columns.

field is the property name to display in the column.

label is the table heading to display in the column.

width is the width of the column.

numeric indicates whether the column is numeric.

The columns are displayed in the way they’re listed in the columns array.

So ID is first, First Name is second, and Last Name is third.

Custom Table

We can add other styles.

To make columns customizable, we can populate slots for the content.

We can use the b-table-column to do that:

<template>
  <div id="app">
    <b-table :data="data" hoverable>
      <template slot-scope="props">
        <b-table-column field="id" label="ID" width="40" numeric>{{ props.row.id }}</b-table-column>

        <b-table-column field="firstName" label="First Name">{{ props.row.firstName }}</b-table-column>

        <b-table-column field="lastLame" label="Last Name">{{ props.row.lastName }}</b-table-column>
      </template>

      <template slot="empty">
        <section class="section">
          <div class="has-text-centered">
            <p>Nothing here.</p>
          </div>
        </section>
      </template>
    </b-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      data: [
        { id: 1, firstName: "jane", lastName: "smith" },
        { id: 2, firstName: "joe", lastName: "smith" },
        { id: 3, firstName: "alex", lastName: "green" }
      ],
      columns: [
        {
          field: "id",
          label: "ID",
          width: "40",
          numeric: true
        },
        {
          field: "firstName",
          label: "First Name"
        },
        {
          field: "lastName",
          label: "Last Name"
        }
      ]
    };
  }
};
</script>

We filled the default slot with b-table-column components.

The props variable has the table data.

We access the with props.row as we did in the code.

The empty slot lets us show something when there’s no data to show in the table.

We replaced the columns prop with the slots.

We can add the bordered, striped, narrowed, hoverable, loading, focusable, and mobile-cards props to set the table options.

mobile-cards means the rows appear as cards on mobile.

The rest is self-explanatory.

In the example above, we added hoverable to b-table to make the rows highlight when hovered.

With Buefy, we can create a table, with the b-table component.

We can either pass in the columns prop to set the columns, or we can use slots to fill the content.

There are also other customization options.

Categories
JavaScript Vue

Add a Dropdown to a Vue App vue-select

We can add a dropdown easily with the vue-select package.

First, we install the package by running:

npm install vue-select

Then we register the plugin by writing:

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");

We register the component with:

Vue.component("v-select", vSelect);

and added the required CSS with:

import 'vue-select/dist/vue-select.css';

Then we can create a basic drop down in our component by writing:

<template>
  <div id="app">
    <v-select :options="['apple', 'orange']"></v-select>
  </div>
</template>

<script>
export default {};
</script>

We passed in an array of strings, which will be the display text and the value.

Also, we can pass in an array of objects:

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

<script>
export default {
  data() {
    return {
      options: [
        { value: "apple", text: "Apple" },
        { value: "orange", text: "Orange" }
      ]
    };
  }
};
</script>

We have the options array, and we set the label prop to choose the property to display to the user.

We set it to text, so we display the value of the text property of each entry to the user.

To get the value selected, we can bind the selected value to a state with the v-model directive:

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

<script>
export default {
  data() {
    return {
      options: [
        { value: "apple", text: "Apple" },
        { value: "orange", text: "Orange" }
      ],
      selected: ""
    };
  },
};
</script>

Now we’ll get the object selected if we pick one from the list.

To assign the value property’s value to selected, we can pass in a function to the reduce prop:

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

<script>
export default {
  data() {
    return {
      options: [
        { value: "apple", text: "Apple" },
        { value: "orange", text: "Orange" }
      ],
      selected: ""
    };
  },
  methods: {
    reduce(fruit) {
      return fruit.value;
    }
  }
};
</script>

Now the value of value is set as the value of selected when we pick our choice.

To add a placeholder, we can use the placeholder prop:

<template>
  <div id="app">
    <v-select
      label="text"
      placeholder="choose a fruit"
      :reduce="reduce"
      v-model="selected"
      :options="options"
    ></v-select>
    <p>{{selected}}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      options: [
        { value: "apple", text: "Apple" },
        { value: "orange", text: "Orange" }
      ],
      selected: ""
    };
  },
  methods: {
    reduce(fruit) {
      return fruit.value;
    }
  }
};
</script>

Now we’ll see ‘choose a fruit’ before we make a choice.

When we click ‘x’ to clear the selection, we’ll see the placeholder again.

We can use the vue-select package to add a customizable drop-down easily.

It can bind to states with v-model and add a placeholder with the placeholder prop.

Categories
JavaScript Vue

Basic Vuex Store Example

Vuex is one state management that’s made to work with Vue apps.

To use it, we install it by running:

npm i vuex

Then we can register the Vuex plugin and create a basic Vuex store with:

import Vue from "vue";
import App from "./App.vue";
import Vuex from "vuex";

Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
    }
  }
});

Vue.config.productionTip = false;

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

The store is created with the Vuex.Store constructor:"

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
    }
  }
});

The object we passed into the constructor has the state property with the count state inside it.

The initial value of count is 0.

The mutations property has methods that change the state.

We have the increment method which takes the state parameter.

It has the same content as the state property above it.

So we can run state.count++ to increment the value of the count state.

To make the store available to the rest of our app, we put store into the object we passed into the Vue constructor.

Then in a component, we can use the store as follows:

<template>
  <div id="app">
    <button @click="increment">Increment</button>
    <p>{{count}}</p>
  </div>
</template>

<script>
export default {
  computed: {
    count() {
      return this.$store.state.count;
    }
  },
  methods: {
    increment() {
      this.$store.commit("increment");
    }
  }
};
</script>

We have this.$store, which is the Vuex store. We have this object since we registered the Vuex plugin and put the store into the object we passed into the Vue constructor.

this.$store.state.count has the count state’s value.

And this.$store.commit lets us commit values to the store.

The 'increment' indicates that we call the increment method in the mutations property in the object we pass into the Vuex.Store constructor.

We also have an Increment button to call increment.

Now when we click the button, we’ll see the count value displayed below the button go up.

The commit method takes a 2nd argument, which is the payload.

So we can write:

import Vue from "vue";
import App from "./App.vue";
import Vuex from "vuex";

Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state, payload) {
      state.count += payload;
    }
  }
});

Vue.config.productionTip = false;

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

and write:

<template>
  <div id="app">
    <button @click="increment">Increment</button>
    <p>{{count}}</p>
  </div>
</template>

<script>
export default {
  computed: {
    count() {
      return this.$store.state.count;
    }
  },
  methods: {
    increment() {
      this.$store.commit("increment", 2);
    }
  }
};
</script>

to increment by 2 instead of 1 when we click.

We have:

this.$store.commit("increment", 2);

instead of:

this.$store.commit("increment");

and:

mutations: {
  increment(state, payload) {
   state.count += payload;
  }
}

instead of:

mutations: {
  increment(state,) {
    state.count ++;
  }
}

payload is the 2 we passed in.

A basic Vuex store can let us store an app-wide state easily.

We just have to commit mutations to set the state and get the state from the store via the $this.store.state property.

We can return the latest value in the computed property so we can use it.

Categories
JavaScript Vue

Add a Numeric Input to a Vue App with vue-numeric

We can add a numeric input to our Vue app with the vue-numeric package.

We can install it by running:

npm install vue-numeric --save

Then we can register the plugin by writing the following in main.js:

import Vue from "vue";
import App from "./App.vue";
import VueNumeric from "vue-numeric";

Vue.use(VueNumeric);

Vue.config.productionTip = false;

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

to register the VueNumeric plugin globally.

Then we can write:

<template>
  <div id="app">
    <vue-numeric currency="$" separator="," v-model="price"></vue-numeric>
    <p>{{price}}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      price: 0
    };
  }
};
</script>

We have the vue-numeric component.

It takes the currency prop to prepend a currency symbol to the input.

separator adds the separator to our input when it’s displayed.

v-model binds the inputted value to the price state.

The currency symbol and the separator are only displayed in the input when we move away from the input.

The value that’s set to price is still what we typed in, except when we type in something that’s not a whole number.

By default, it doesn’t let us enter decimals.

We can add the :precision prop to let us enter decimals.

There’s also the minus prop to let us enter negative numbers.

Also, the placeholder prop lets us add placeholders.

The output data type can be changed with output-type.

The empty-value prop lets us set a default value for the state.

So we can write:

<template>
  <div id="app">
    <vue-numeric currency="$" separator="," v-bind:precision="2" v-model="price"></vue-numeric>
    <p>{{price}}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      price: 0
    };
  }
};
</script>

to allow up to 2 decimals to be entered.

The entered value will be converted automatically to the specified format when we move our focus away from the input.

The vue-numeric package lets us add a currency input easily.

It can be adjusted to use a different thousands separator, the numver of decimal digits, and more.