Displaying a Vue.js component only when a specific API condition is satisfied: A step-by-step guide

After experimenting with v-if, I encountered the following error: Uncaught TypeError: Cannot read property '0' of undefined

I have identified the issue to be related to the fact that the code cannot execute without the data being fetched first. However, I am unsure of how to make this happen only when the Enter key is pressed.

If I remove v-if="weather.weather[0].main=='Clouds'" and v-if="weather.weather[0].main=='Clear'", the code functions normally. Yet, all the animations occur simultaneously when I do this.

Below is the code snippet:

<template>
  <div id="container" :class="containerTemperature">
    <h1>Better<br>Weather</h1>
    <main id="app" :class="appTemperature">
        <div class="search-box">
          <input 
            type="text" 
            class="search-bar" 
            placeholder="Search..."
            v-model="query"
            @keypress="fetchWeather" 
          />
        </div>
        
        

        <CloudsAnimation v-if="weather.weather[0].main=='Clouds'">
        </CloudsAnimation>

        <SunAnimation v-else-if="weather.weather[0].main=='Clear'">
        </SunAnimation>

        <NoAnimation v-else>
        </NoAnimation>

        <div class="weather-wrap" v-if="typeof weather.main != 'undefined'">
          <div class="location-box">
            <div class="location">{{ weather.name }}, {{ weather.sys.country }}</div>
            <div class="date">{{ dateBuilder() }}</div>
          </div>
          <div class="weather-box">
            <div class="temp">{{ Math.round(weather.main.temp) }}°c</div>
            <div class="weather">{{ weather.weather[0].main }}</div>
          </div>
        </div>
    </main>
  </div>
</template>

<script>
import CloudsAnimation from "./components/CloudsAnimation"
import SunAnimation from "./components/SunAnimation"
import NoAnimation from "./components/NoAnimation"

export default {
  name: 'App',
  components: { 
    CloudsAnimation, 
    SunAnimation,
    NoAnimation
    },
  data () {
    return {
      api_key: '08f1525958fbc6584f628b6dac25a906',
      url_base: 'https://api.openweathermap.org/data/2.5/',
      query: '',
      weather: {}
    }
  },
  computed: {
    containerTemperature: function () {
    return {
      'warm-container': typeof this.weather.main != 'undefined' && this.weather.main.temp > 20,
      'cold-container': typeof this.weather.main != 'undefined' && this.weather.main.temp < 9
    }
  }, appTemperature: function () {
    return {
      'warm': typeof this.weather.main != 'undefined' && this.weather.main.temp > 20,
      'cold': typeof this.weather.main != 'undefined' && this.weather.main.temp < 9
    }
  }
  },
  methods: {
    fetchWeather (e) {
      if (e.key == "Enter") {
        
        fetch(`${this.url_base}weather?q=${this.query}&units=metric&APPID=${this.api_key}`)
          .then(res => {
            return res.json();
          }).then(this.setResults)
          .then(this.query = "");
      } 
    },
    setResults (results) {
      this.weather = results;
    },
    dateBuilder () {
      let d = new Date();
      let months = ["January", "February", "March", "August", "September", "October", "November", "December"];
      let days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

      let day = days[d.getDay()];
      let date = d.getDate();
      let month = months[d.getMonth()];
      let year = d.getFullYear();

      return `${day} ${date} ${month} ${year}`;
    }
  }
}
</script>

<style lang="scss">
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Rajdhani:wght@300&display=swap');


* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;

  body {
    font-family: 'Montserrat', sans-serif;

    #container {
      position: relative;
      display: flex;
      ...
    }
  }
}

</style>

Answer №1

Prior to accessing the object's property, confirm that it has been retrieved by including an additional verification step:

 <CloudsAnimation v-if="weather && weather.weather[0].main=='Clouds'">
        </CloudsAnimation>

Also, when declaring data, initialize the property as null:

data () {
    return {
      api_key: '08f1525958fbc6584f628b6dac25a906',
      url_base: 'https://api.openweathermap.org/data/2.5/',
      query: '',
      weather: null
    }

This conditional statement checks if the property is null before rendering. If it is null, it won't render, but if it's not null, it will check the data. Ensure to apply this check to each component or on a parent element.

Answer №2

It's clear that explaining the issue is unnecessary. I like to keep my templates free of lengthy if statements and instead opt for computed properties. To simplify things, I would switch out the if statements for computed properties when dealing with extensive checks for null values. For instance:

<CloudsAnimation v-if="computedWeather === 'Clouds'"></CloudsAnimation>

<SunAnimation v-else-if="computedWeather === 'Clear'"></SunAnimation>

And here is the computed property:

computedWeather: function() {
  return (this.weather && this.weather.weather && this.weather.weather[0] && this.weather.weather[0].main) || null;
}

As you can see, using a computed property is much cleaner than a long if check in the template.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When using the map function, I am receiving an empty item instead of the intended item based on a condition

Need assistance with my Reducer in ngRx. I am trying to create a single item from an item matching an if condition, but only getting an empty item. Can someone please help me out? This is the code for the Reducer: on(rawSignalsActions.changeRangeSchema, ...

Change the color of the Material UI InputLabel

Seeking assistance with my input label: <InputLabel>NAME</InputLabel> The text is currently displaying in white, which makes it difficult to read against the white background. Can someone provide guidance on how I can change the color to blac ...

The Angular app.component.html is failing to display the newly added component

Having some trouble rendering my new component in the browser. I've set up a fresh project using the Angular CLI and created a component named list-employees. Upon running ng serve -o, the project compiles without errors, but the browser displays a b ...

When I submit 'name' through Postman, ValidatorExpress notifies me that the input for 'name' is missing

Whenever I use the 'POST' method in Postman with the URL http://localhost:7777/register, and select the options Body and row to paste the object {name: 'Martin}, why does it return "You must supply a name!" from the array ["You must supply a ...

Deciphering the intricacies of using middleware in Express -

As a novice, I find it challenging to interpret documentation, but I can grasp the code's meaning once I see it in action. Take app.use([path,] callback [, callback...]), for example. I know how to utilize this method, yet I still struggle with unde ...

Store and retrieve user input using JavaScript or JSON

Can someone please assist me in finding a solution to this problem? I have 3 input fields where users can type in their answers. There is also a "SAVE" button that allows users to download their input values into a file.txt. Additionally, there is a "choos ...

Launching an external JavaScript from within a separate JavaScript file

I'm in the process of developing a virtual 'directory' for various locations in my city to assist fellow students. Here's the concept: On a map, I've pinned all the locations Clicking on these pins triggers a JavaScript funct ...

What is the best way to integrate ES6 ReactJS code into an Express application?

I am trying to initially render my ReactJS application on the server using ExpressJS. Although I have been able to import ES6 modules using require(), the module crashes upon loading because it contains ES6 code (ES6 import and export). Index Route var ...

Creating a virtual URL version for the Ultraviolet App express server in response to a client's access

Ultraviolet App is an innovative library that leverages Ultraviolet technology to bypass various service restrictions. My goal is to utilize it for a specific task: The requirement involves a list of services, where clicking on one triggers a request to t ...

Organize nested level components in react native into a more structured order

Currently, I am working with some JSON data that has the following structure: const data = { "stores": [ { "name": "s1", "id": "6fbyYnnqUwAEqMmci0cowU", "customers": [ { "id": "4IhkvkCG9WWOykOG0SESWy", ...

Using Javascript to Pass Variables to Ajax with getElementById

Struggling to figure out how to effectively pass a Javascript Variable to Ajax and then post it to PHP? While both the Javascript and PHP code are functioning as expected, the challenge lies in transferring the Javascript Variable to Ajax for subsequent ...

Deliver XML document to client from an ASP.NET MVC webpage

I need help with an ASP.NET MVC web page that requires user input to create an XML file using a javascript function. After the user enters information and clicks a button, how can I display the XML created by the javascript method? In the .cshtml file: Fo ...

Counting the number of key-value pairs for a specific key in a JSON data can be achieved by implementing

Is there a way to determine if __metadata and ItemToEkbeNav are the root elements for their children who have key-value pairs? I've attempted various methods such as Object.keys().length and Array.isArray(), but haven't been able to retrieve the ...

What is the best way to superimpose an image onto a canvas?

I am working on a cool project where I have created a canvas that displays matrix binary code raining down. However, I would like to enhance it by adding an image overlay on top of the canvas. Here is my current setup: <div class="rain"> ...

Header Express does not contain any cookies, which may vary based on the specific path

In my express.js app, I have two controllers set up for handling requests: /auth and /posts. I've implemented token authorization to set the Authorization cookie, but I'm encountering an issue when making a request to /posts. The request goes th ...

Executing multiple functions with onPress in React Native

When I press onPress using TouchableOpacity, I am attempting to invoke multiple functions. Here's an example: functionOne(){ // perform an action } functionTwo(){ // execute something } <TouchableHighlight onPress{() => this.functionOne()}/& ...

Issue with triggering blur event in Internet Explorer while using Angular 2+

The issue discussed in the Blur not working - Angular 2 thread is relevant here. I have a custom select shared component and I am attempting to implement a blur event to close it when the component loses focus. // HTML <div (blur)="closeDropDown()" t ...

What is the best way to pass the value of a selected option to an express server

<label for="exampleFormControlSelect1"> <strong>Please Select the Number of PDFs to Merge:</strong> </label> <select class="form-control" id="exampleFormControlSelect1"> <option name=" ...

Navigating through the maze of ES6 imports and dealing with the complexities

Currently, I am delving into React and creating my own components. However, the issue of project organization has arisen. Here is the structure of my project: Project_Folder - Components - Form - index.js - form.less - package.js ...

Thymeleaf not triggering JQuery click event

Currently working on a Spring Boot site where I have a list of elements, each containing a link. The goal is to trigger a javascript function when these links are clicked. <div class="col-sm-4" th:each="product : ${productsList}"> <!-- Code... ...