When the component is initialized, the computed property is not being evaluated

My maps component initializes a Google map, adds markers based on props passed from the parent, and sets the correct bounds of the map. However, the markers are added through a computed property to make it reactive. Everything seems to be working fine, except that the addMarkers function within my computed properties does not evaluate when the page and component are loaded.

The strange thing is that when I open Vue Devtools and click on the maps component, addMarkers immediately evaluates and updates the map correctly.

Any assistance would be greatly appreciated :-)

<template lang="pug" >

div.google-map(id="results-map")

</template>
<script>

import Gmaps from 'gmaps';

export default {
    name: 'maps',
    props: {
        results: {
            type: Array,
            required: true
        }
    },
    data() {
        return {
            map: {},
            bounds: {}
        }
    },
    computed: {
        addMarkers() {
            this.results.forEach((result) => {
                if (result.latitude && result.longitude) {
                    var marker = this.map.addMarker({
                        lat: result.latitude,
                        lng: result.longitude,
                        title: result.name,
                        infoWindow: {
                            content: result.name
                        }
                    });
                }
                this.bounds.extend(marker.position)
            });
            this.map.fitBounds(this.bounds)
        }
    },
    mounted() {
        this.map = new Gmaps({
            div: '#results-map',
            lat: 0,
            lng: 0,
            zoom: 15
        });
        this.bounds = new google.maps.LatLngBounds();
    }
}
</script>

Answer №1

A computed property is designed to return a specific value, whereas your addMarkers function does not return any value.

In addition, a computed property is only calculated when it is requested. Therefore, if the markers are not displayed when the component is created, it is likely because the computed property is never requested.

However, when you inspect the developer tools, VueJS attempts to evaluate the computed property and runs the code. As a result, your code adds the markers, even though it is not within a computed property.

There are several ways to address this issue:

Option 1: Force the evaluation of the computed property on the mounted hook:

mounted() {
    this.map = new Gmaps({
        div: '#results-map',
        lat: 0,
        lng: 0,
        zoom: 15
    });
    this.bounds = new google.maps.LatLngBounds();
    this.addMarkers()
}

Option 2: Turn your addMarkers function into a method that can be executed whenever necessary:

import Gmaps from 'gmaps';

export default {
    name: 'maps',
    props: {
        results: {
            type: Array,
            required: true
        }
    },
    data() {
        return {
            map: {},
            bounds: {}
        }
    },
    methods: {
        addMarkers() {
            this.results.forEach((result) => {
                if (result.latitude && result.longitude) {
                    var marker = this.map.addMarker({
                        lat: result.latitude,
                        lng: result.longitude,
                        title: result.name,
                        infoWindow: {
                            content: result.name
                        }
                    });
                }
                this.bounds.extend(marker.position)
            });
            this.map.fitBounds(this.bounds)
        }
    },
    mounted() {
        this.map = new Gmaps({
            div: '#results-map',
            lat: 0,
            lng: 0,
            zoom: 15
        });
        this.bounds = new google.maps.LatLngBounds();
        this.addMarkers()
    }
}

For instance, if you want the markers to update when the results prop changes, you can utilize the watch property:

export default {
    ...
    watch: {
        results: {
            deep: true,
            handler () {
                this.addMarkers()
            }
        }
    }
}

Answer №2

The addMarkers computed property doesn't seem to be utilized in your code. Perhaps you could consider converting it into a method and invoking it within the mounted function for better functionality.

Answer №3

To tackle changes in the results occurring externally to your component:

  • Convert the addMarkers() computed property into a watcher for the results.

This ensures that the code is triggered every time the results prop alters.

Furthermore, considering you are implementing some DOM manipulation logic within your mounted() hook:

  • Encase the logic of the results watcher inside a Vue.nextTick() to guarantee its execution only after the DOM is ready for modification (i.e., once you've set up <google-maps>):

Vue.nextTick(): Postpone the callback's execution until after the subsequent DOM update cycle. Use it right after modifying some data to await the DOM update.

Hence, your updated watch block (formerly the addMarkers() computed property) will be as follows:

watch: {                                                                 // line changed
    results: {                                                           // line changed
        deep: true,                                                      // line changed
        handler () {                                                     // line changed
            Vue.nextTick(() => {                                         // line changed
                this.results.forEach((result) => {
                    if (result.latitude && result.longitude) {
                        var marker = this.map.addMarker({
                            lat: result.latitude,
                            lng: result.longitude,
                            title: result.name,
                            infoWindow: {
                                content: result.name
                            }
                        });
                    }
                    this.bounds.extend(marker.position)
                });
                this.map.fitBounds(this.bounds)
            });                                                         // line changed
        }                                                               // line changed
    }
},

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

Encountering the 'unsupported_grant_type' error while attempting to retrieve an access token from the Discord API

Having trouble implementing Discord login on my website. When trying to exchange the code for an access token from https://discord.com/api/oauth2/token, I keep getting the error { error: 'unsupported_grant_type' }. This is my code: const ...

Understanding the readability of JavaScript arrays.ORDeciphering

Recently, I've been working with a JSON OBJECT that looks something like this { "kay1": "value1", "key2": "value2", "key3":{ "key31": "value31", "key32": "value32", "key33": "value33" } } However, I am interested in converting it ...

Having trouble integrating Socket.io with Express.js?

I'm currently attempting to connect socket.io with express.js: var socket = require('./socket_chat/socket.js'); var express = require('express'), app = module.exports.app = express(); var io = require('socket.io&apo ...

After deploying the VueJS app to Firebase, the page appears to be blank and devoid of

I attempted to launch two applications on Google Firebase, One was relatively straightforward, consisting of just an App.vue file with a function that sends information to the Firebase Database. The other app was more complex, involving several Vue compo ...

What is the best way to use checkboxes in VueJS to apply filters on a loop and display specific results?

I'm struggling with implementing filters using checkboxes on a list of results and could really use some assistance. Currently, only the 'All' option is working for applying any filtering logic. Here is how my HTML looks like with the filt ...

Is there a way to dispatch an event from one Angular ui-router view to another view?

In order to change the login button to display "logged in as xxx" after authentication, I have structured my page into three views: header, content, footer. The login button is located in the header view. Upon clicking login, it transitions to the "app.log ...

Mysterious dual invocation of setState function in React

My component is designed to display a list of todos like: const todosData = [ { id: 1, text: "Take out the trash", completed: true }, { id: 2, text: "Grocery shopping", completed: false }, ]; ...

Modifying the image height in a column using Bootstrap and JSON data

My webpage is dynamically generating images from a JSON file through a JavaScript file. However, the images are displaying at different heights, and I want each column to adjust to the height of the image to eliminate any gaps. Particularly, data with the ...

Is there a way to assign API data as inner HTML using Lit?

Need help setting inner html of html elements with a get request Any suggestions on how to achieve this? import { LitElement, html, css } from "lit"; import { customElement } from "lit/decorators.js"; import axios from "axios" ...

Utilize AngularJS to Capitalize the First Letter and the Letter Following a Dot (.)

I am seeking a solution to capitalize the first letter in a given string, like so: sumo => Sumo Additionally, I need to capitalize strings in the following format: Dr.ravi kumar => Dr.Ravi kumar Although I have implemented an Angular filter that ...

Exploring the Possibilities: Incorporating xlsx Files in Angular 5

Is there a way to read just the first three records from an xlsx file without causing the browser to crash? I need assistance with finding a solution that allows me to achieve this without storing all the data in memory during the parsing process. P.S: I ...

Getting a specific piece of information from a JSON file

I am encountering an issue with my JSON file collection. When I access it through http://localhost:5000/product/, I can see the contents without any problem. However, when I try to retrieve a specific product using a link like http://localhost:5000/product ...

Cease the execution of promises as soon as one promise is resolved

Using ES6 promises, I have created a function that iterates over an array of links to search for an image and stops once one is found. In the implementation of this function, the promise with the fastest resolution is executed while others continue to run ...

"Obtaining header requests in node.js: A step-by-step guide

Currently, as I work on developing the elasticsearch API application, my task involves retrieving the header request from an AJAX call on the server side. The AJAX request is as follows: $.ajax({ url: 'http://localhost:3002/api/v1/getAutoSu ...

Having trouble with Array.filter functionality

Despite the multitude of discussions on this topic, I have not been successful in using the Array.filter method to remove an item from a string-based Array. Below is an example of the filter method being used in the context of mutating a Vuex store. UPDAT ...

Implementing b-tooltip from Bootstrap-vue on a b-table

Utilizing bootstrap-vue to display data on a b-table, I have truncated long text and display the original when hovering over it using the title prop. It works well with custom CSS, but I would like to implement b-tooltip. <b-table hover sticky-hea ...

Tips on ensuring Vuex reacts to changes in attributes/properties within objects contained in lists

Within my Vuex store file, there is a variable that starts as an empty list. This list is meant to hold user objects which have properties such as id, firstname, lastname, and more. export const state = () => ({ users: [] }) As the application runs, ...

When trying to view the page source in Next.js, the page contents do not display

I made the decision to switch my project from CRA to nextjs primarily for SEO purposes. With Server Side Rendering, the client receives a complete HTML page as a response. However, when I check the source of my landing page, all I see is <div id="__next ...

Using Google Apps Script to upload a text file to Google Drive

It seems like uploading a file should be straightforward. However, I'm struggling with understanding blobs. function createFileUploader() { var app = UiApp.createApplication(); var panel = app.createVerticalPanel().setId('panel'); v ...

Using the ESNEXT, Gutenberg provides a way to incorporate repeater blocks that

If you're like me, trying to create your own custom Gutenberg repeater block with a text and link input field can be quite challenging. I've spent hours looking at ES5 examples like this and this, but still feel stuck. I'm reaching out for ...