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
React

react-i18next NPM Package — Trans Component with Lists and I18nextProvider

If we want to add localization to a React app, we can use the react-i18next NPM package to do it.

In this article, we’ll look at how to use the Trans and I18nextProvider components to render our translations.

Trans Component and Lists

We can use the Trans component with lists.

For example, we can write:

import React from "react";
import i18n from "i18next";
import { initReactI18next, Trans } from "react-i18next";

i18n.use(initReactI18next).init({
  resources: {
    en: {
      translation: {
        list_map: "My dogs are named: <1></1>"
      }
    }
  },
  lng: "en",
  fallbackLng: "en",
  interpolation: {
    escapeValue: false
  }
});

export default function App() {
  return (
    <div className="App">
      <Trans i18nkey="list_map">
        My dogs are named:
        <ul i18nIsDynamicList>
          {["mary", "max"].map((dog) => (
            <li>{dog}</li>
          ))}
        </ul>
      </Trans>
    </div>
  );
}

We have the list_map translation which we load with the Trans component.

i18nkey has the key for the translations.

The i18nIsDynamicList prop lets us render lists in our translations.

Components Array

We can interpolate translations with an array of components.

For example, we can write:

import React from "react";
import i18n from "i18next";
import { initReactI18next, Trans } from "react-i18next";

i18n.use(initReactI18next).init({
  resources: {
    en: {
      translation: {
        hello: "hello great <0>{{what}}</0>"
      }
    }
  },
  lng: "en",
  fallbackLng: "en",
  interpolation: {
    escapeValue: false
  }
});

export default function App() {
  return (
    <div className="App">
      <Trans
        i18nKey="hello"
        defaults="hello <0>{{what}}</0>"
        components={[<strong>{{ what: "universe" }}</strong>]}
      />
    </div>
  );
}

We have an array of components that we passed into the components prop.

The <0> tag indicates the index of the component will be interpolated.

We map the values to the interpolation placeholder with an object.

defaults has the default translation string.

i18nKey has the translation key.

I18nextProvider

We can initialize the i18n instance with the I18nextProvider .

For example, we can write:

index.html

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import i18n from "i18next";
import { initReactI18next, I18nextProvider } from "react-i18next";

i18n.use(initReactI18next).init({
  resources: {
    en: {
      translation: {
        hello: "hello world"
      }
    }
  },
  lng: "en",
  fallbackLng: "en",
  interpolation: {
    escapeValue: false
  }
});

const rootElement = document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <I18nextProvider i18n={i18n}>
      <App />
    </I18nextProvider>
  </React.StrictMode>,
  rootElement
);

App.js

import React from "react";
import { useTranslation } from "react-i18next";

export default function App() {
  const { t } = useTranslation();

  return <div className="App">{t("hello")}</div>;
}

The I18nextProvider wraps around the App so that we initial the i18n object for the whole app.

Then in our App component, we can get the translations.

Conclusion

We can use the Trans component to render lists. Also, we have the I18nProvider to wrap around app to enable translations in our whole app.

Categories
React

react-i18next NPM Package — Trans Component

If we want to add localization to a React app, we can use the react-i18next NPM package to do it.

In this article, we’ll look at how to use the Trans component to render our translations.

Trans Component

The Trans component lets render translations that have dynamic text.

For example, we can user it by writing:

import React from "react";
import i18n from "i18next";
import { useTranslation, initReactI18next, Trans } from "react-i18next";

i18n.use(initReactI18next).init({
  resources: {
    en: {
      translation: {
        nameTitle: "mr",
        userMessagesUnread:
          "Hello <1>{{name}}</1>, you have {{count}} unread message. <5>Go to message</5>.",
        userMessagesUnread_plural:
          "Hello <1>{{name}}</1>, you have {{count}} unread messages.  <5>Go to messages</5>."
      }
    }
  },
  lng: "en",
  fallbackLng: "en",

interpolation: {
    escapeValue: false
  }
});

const count = 2;
const name = "james";

export default function App() {
  const { t } = useTranslation();

  return (
    <div className="App">
      <Trans i18nKey="userMessagesUnread" count={count}>
        Hello <strong title={t("nameTitle")}>{{ name }}</strong>, you have
        {{ count }} unread message. <a href="msgs">Go to messages</a>
      </Trans>
    </div>
  );
}

We set the i18nKey to the translation key to get the item.

count passes th count value to the item.

Also, we render the nameTitle translation inside the Trans tags.

The positions of the text will automatically be matched by react-i18next to render the translations in the right places.

We can also pass in the values we interpolate as props.

For example, we can write:

import React from "react";
import i18n from "i18next";
import { useTranslation, initReactI18next, Trans } from "react-i18next";

i18n.use(initReactI18next).init({
  resources: {
    en: {
      translation: {
        hello:
          "hello <italic>beautiful beautiful</italic> <bold>{{what}}</bold>"
      }
    }
  },
  lng: "en",
  fallbackLng: "en",

interpolation: {
    escapeValue: false
  }
});

export default function App() {
  return (
    <div className="App">
      <Trans
        i18nKey="hello"
        defaults="hello <italic>beautiful</italic> <bold>{{what}}</bold>"
        values={{ what: "world" }}
        components={{ italic: <i />, bold: <strong /> }}
      ></Trans>
    </div>
  );
}

We have the Trans component with the trannslation added to it.

The defaults prop has the default translation to render if the translation with the given i18nkey isn’t found.

values has the object with the values, we interpolate into the curly braces.

components has the components that we want to interpolate in place of the tags with the given name.

We can also use some simple elements directly in our translations.

For example, we can write:

import React from "react";
import i18n from "i18next";
import { useTranslation, initReactI18next, Trans } from "react-i18next";

i18n.use(initReactI18next).init({
  resources: {
    en: {
      translation: {
        hello: "Hello <1>{{name}}</1>."
      }
    }
  },
  lng: "en",
  fallbackLng: "en",
  interpolation: {
    escapeValue: false
  }
});

const name = "james";

export default function App() {
  return (
    <div className="App">
      <Trans i18nkey="hello">
        Hello <strong>{{ name }}</strong>.
      </Trans>
    </div>
  );
}

We put the HTML strong element between the tags and it’ll be rendered.

It’ll also get the correct translation for plurals automatically:

import React from "react";
import i18n from "i18next";
import { initReactI18next, Trans } from "react-i18next";

i18n.use(initReactI18next).init({
  resources: {
    en: {
      translation: {
        newMessages: "You got one message.",
        newMessages_plural: "You got {{count}} messages."
      }
    }
  },
  lng: "en",
  fallbackLng: "en",
  interpolation: {
    escapeValue: false
  }
});

const messages = ["message one", "message two"];

export default function App() {
  return (
    <div className="App">
      <Trans i18nkey="newMessages" count={messages.length}>
        You got {{ count: messages.length }} messages.
      </Trans>
    </div>
  );
}

We set the i18nkey to newMessages and set the count to the length of messages .

Then we get get the correct translation according to whether messages.length is 1 or not 1.

The _plural suffix indicates the plural version of the translation without the suffix.

Conclusion

We can use the Trans component to render HTML and plural translations.