Hands On

Show the Weather Forecast in a NativeScript with Vue.js iOS and Android Application

By Nic Raboy | 20 May 2019

About a week ago I had written a tutorial around using the HERE Weather API in a NativeScript with Angular application. This was an extension to my popular tutorial which focused on strictly Angular with the HERE Weather API. However, if you’re a NativeScript developer, you probably know that Angular isn’t the only way to do business.

In this tutorial we’re going to explore using the HERE Weather API in NativeScript, but this time using Vue.js and simple JavaScript.

To get an idea of what we want to accomplish, take a look at the following image:

ns-vue-weather

In the above image you’ll notice a nicely formatted list view with the 7 day local forecast. This is an application that works on both Android and iOS because of NativeScript, however it was made possible with Vue.js and the HERE Weather API.

Create a New NativeScript with Vue.js Project

The first step towards being successful with this project is to create the project and install any of the dependencies. Assuming that you’ve got the Vue CLI installed as well as the NativeScript CLI, execute the following:

vue init nativescript-vue/vue-cli-template ns-vue-project

The above command will create a new project. When asked, go ahead and choose the defaults.

After creating the project, we technically don’t need anything else. However, in an effort to make our application as slick as possible, we’re going to download a dependency to format our date and time information.

Navigate into your project directory and execute the following command:

npm install moment --save

The above Moment.js library is pretty much the standard when it comes to working with dates and times in JavaScript. Again, it isn’t absolutely necessary, but it will help us in the future.

Now we can start adding our code to interact with the HERE Weather API.

Communicate with the HERE Weather API using HTTP

Because of how Vue.js works, we’re able to have all of our component code in the same file. Rather than introducing new complexity, we’re going to leverage a component that already exists rather than create a new one.

Open the project’s app/components/App.vue file and add the following boilerplate code:

<template>
    <Page>
        <ActionBar title="TRACY, CA"/>
        <GridLayout columns="*" rows="*">
        </GridLayout>
    </Page>
</template>

<script >
    import * as http from "http";
    import * as moment from "moment";
    export default {
        data() {
            return {
                weather: []
            }
        },
        mounted() { },
        methods: { },
        filters: { }
    }
</script>

<style scoped>
    ActionBar {
        background-color: #53ba82;
        color: #ffffff;
    }

    .message {
        vertical-align: center;
        text-align: center;
        font-size: 20;
        color: #333333;
    }
</style>

In the above code you can see that we’ve imported the NativeScript HTTP module which we’ll be using for consuming data from the REST API. We’re also importing Moment.js which we’ll use later.

The goal here is to get weather information and store it in a weather array to be used in the <template> area. To do this, let’s focus on creating some methods with Vue.js.

Since the HERE Weather API requires quite a few query parameters, instead of just concatenating them directly, we’re going to create a helper function for the job:

encodeQueryParameters(params) {
    const encodedParameters = [];
    for(const key in params) {
        if(params.hasOwnProperty(key)) {
            encodedParameters.push(key + "=" + encodeURIComponent(params[key]));
        }
    }
    return "?" + encodedParameters.join("&");
}

If you’ve used JavaScript for a while, you’ve probably seen some variation of the above function a thousand times. We’re just accepting an object and encoding it to be compatible query parameters.

We can create a getWeather method that makes use of it:

getWeather(appId, appCode, position) {
    const params = {
        product: "forecast_7days_simple",
        latitude: position.latitude,
        longitude: position.longitude,
        app_id: appId,
        app_code: appCode
    }
    http.getJSON("https://weather.api.here.com/weather/1.0/report.json" + this.encodeQueryParameters(params)).then(result => {
        this.weather = result.dailyForecasts.forecastLocation.forecast;
    }, error => {
        console.error(error);
    });
},

We’re constructing our parameters object based on the HERE Weather API documentation. When we have our object, we are encoding it to query parameters and using it in a getJSON request. A lot of information comes back, but we’re only storing the forecast information.

To get an idea of what our methods look like completed, they might look like this:

methods: {
    getWeather(appId, appCode, position) {
        const params = {
            product: "forecast_7days_simple",
            latitude: position.latitude,
            longitude: position.longitude,
            app_id: appId,
            app_code: appCode
        }
        http.getJSON("https://weather.api.here.com/weather/1.0/report.json" + this.encodeQueryParameters(params)).then(result => {
            this.weather = result.dailyForecasts.forecastLocation.forecast;
        }, error => {
            console.error(error);
        });
    },
    encodeQueryParameters(params) {
        const encodedParameters = [];
        for(const key in params) {
            if(params.hasOwnProperty(key)) {
                encodedParameters.push(key + "=" + encodeURIComponent(params[key]));
            }
        }
        return "?" + encodedParameters.join("&");
    }
},

We probably want to load the weather information when our application loads. To do this, we can make use of the mounted lifecycle event in Vue.js. To make use of this event, include the following:

mounted() {
    this.getWeather("APP-ID-HERE", "APP-CODE-HERE", { latitude: 37.7397, longitude: -121.4252 });
},

Notice in the mounted event we are only calling the getWeather function that we had previously created. Make sure to swap the app id and app code values with those found in your HERE Developer Portal.

In theory, we now have weather information to work with. It is time we actually render it on the screen. We’ll want to create a ListView in our <template> block like this:

<template>
    <Page>
        <ActionBar title="TRACY, CA"/>
        <GridLayout columns="*" rows="*">
            <ListView for="item in weather" class="list-group">
                <v-template>
                    <GridLayout class="list-group-item" rows="auto, auto" columns="50, *">
                        <Image :src="item.iconLink" rowSpan="2" row="0" col="0" />
                        <Label row="0" col="1">{{ item.highTemperature }}C</Label>
                        <Label :text="item.utcTime" row="1" col="1" />
                    </GridLayout>
                </v-template>
            </ListView>
        </GridLayout>
    </Page>
</template>

There are a few things to notice in the above XML. First you’ll notice that we are only including three pieces of data from our response. We’re displaying the weather icon, the highest temperature of the day and the timestamp. Second you’ll notice that we are adding formatting to our list rows with a GridLayout component.

If we were to run the application, it would work, but the timestamp wouldn’t look too attractive. Also, if you’re in the United States like I am, you’re probably more familiar with Fahrenheit as the measurement. We can fix this.

Transform API Responses with Vue.js Filters

The best way to do transformations in the XML is to make use of Vue.js filters which act as pipes in other technologies. Essentially, we provide a value to the filter and it is transformed into another value.

Let’s take a look at the following two filters:

filters: {
    fahrenheit(value) {
        return ((value * (9 / 5)) + 32).toFixed(2);
    },
    pretty(value) {
        return moment(value).format("MMMM DD, YYYY");
    }
}

In the above code we have a fahrenheit filter and a pretty filter. The fahrenheit filter will apply a formula to convert the temperature to fahrenheit and the pretty filter will use Moment.js to format our date into something more human readable.

To use our filters, we can make some adjustments to the XML:

<GridLayout class="list-group-item" rows="auto, auto" columns="50, *">
    <Image :src="item.iconLink" rowSpan="2" row="0" col="0" />
    <Label row="0" col="1">{{ item.highTemperature }}C / {{ item.highTemperature | fahrenheit }}F</Label>
    <Label :text="item.utcTime | pretty" row="1" col="1" />
</GridLayout>

In the above code, notice that we are using a pipe character and the filter name. When we do this, we are taking the original value, piping it into our filter, then displaying the result of the transformation.

Conclusion

You just saw how to use the HERE Weather API in a NativeScript project that used Vue.js as the core framework. The HERE Weather API does a lot more than just 7 day forecast information, even though it was the focus of this example. As long as your computer is properly configured, you’ll be able to build your project for both Android and iOS with NativeScript.

If you’re more familiar with Angular, you can check out my NativeScript with Angular version here.