Vue3 - Utilizing a method to dynamically alter an input property

Currently, I am in the process of developing a Vue application that incorporates a map feature. The main functionality involves determining whether a given position on the map is over water or land. If the position is over water, I want to iterate through random nearby positions until I find one over land and return those coordinates. This is a simplified version of the code snippet I am using for testing:

snippet from template

<mapbox-marker :lngLat="getPositionOverLand([0,5])" />

corresponding code

const getPositonOverLand = (coords: any, tries=100) => {
      
const newCoords = [coords[0], coords[1]] as [number, number];
      let thisTry = 0;
      while(isOverWater(newCoords) && thisTry < tries){
        newCoords[0] = coords[0] + (Math.random() - 0.5)*0.5
        newCoords[1] = coords[1] + (Math.random() - 0.5)*0.5
        thisTry++;
      }
      if(thisTry === tries)
        throw new Error('No position on land nearby could be found');
  

      coords[0] = newCoords[0];
      coords[1] = newCoords[1];
    }

After debugging the algorithm, it seems to be working well. It usually finds a position on land after a few attempts and returns the coordinates. I have also included a parameter for maximum attempts to avoid infinite loops when trying to find land positions.

The issue I am facing in Vue is that if I change the coordinates within my function, regardless of whether I use a return statement or modify the array directly, the function keeps triggering itself, resulting in an infinite loop.

Is there a way to prevent this behavior and ensure the algorithm runs only once, or have I overlooked something else? Interestingly, just returning the provided coordinates for testing does not lead to an infinite loop.

Answer №1

Uncertain about the source of the reactivity trigger. Based on the provided code, it is difficult to determine as there are no observable reactive variables present; the cause could be located higher up in the chain.

I do notice, however, that

<mapbox-marker :lngLat="getPositionOverLand([0,5])" />
raises a red flag in terms of Vue development, as it has the potential to lead to the issues you have encountered.

Passing a function result as a parameter causes the function to execute every time any parent element triggers a re-render. If anything within that function prompts a re-render (which doesn't seem to be happening here, although without a return statement it's impossible to confirm), it can result in unexpected behavior.

A more effective approach would be to utilize a computed property or store the value in a data object that is updated via a watch method. This ensures that the value is stored and only changes when necessary.

Answer №2

Okay,

As mentioned earlier, the issue arises from every mutation triggering a re-render (although it's still unclear why returning the parameter itself in the function didn't have the same effect).

However, I managed to resolve the problem. Let me share a bit more code than what was initially provided, as another component with asynchronous behavior is involved. Here's how my HTML looks:

<mapbox-map :accessToken="myToken" @loaded="updateMyPosition">
  <mapbox-marker :lngLat="myPosition" />
</mapbox-map>

Now, the position must be a ref that gets updated once the map loads and becomes accessible. This ensures that the data is mutated only once instead of repeatedly running the function.

I also made some changes to the getPositionOverLand function, although its functionality remains essentially the same. I just preferred the recursive approach over using a while loop.

const myPosition = ref([10,10]);

const getPositionOverLand = (coords, currentTry=0, maxTries=100) => {
  if(!isOverWater(coords))
    return coords;

  let newCoords = [
    coords[0] + (Math.random() - 0.5)*0.5,
    coords[1] + (Math.random() - 0.5)*0.5
  ];

  if(currentTry >= maxTries)
    throw new Error('No position on land could be found');

   return (isOverWater(newCoords) && currentTry < maxTries)
      ? getPositonOverLand(coords, currentTry+1, maxTries)
      : newCoords;
}

const updateMyPosition = map => {
  myPosition.value = getPositionOverLand(myPosition.value);
}

While this solution works, I find it not very elegant. I would prefer utilizing the function rather than mutating the ref directly, as it would lead to cleaner usage with v-for loops, for instance, making iteration through the array in the code and updating each value much simpler.

For now, I'll mark this as the answer, but I'm open to changing it if someone suggests a better approach ;)

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

Leverage AJAX to transmit a PHP array to an external JavaScript file

I have a situation where I need to transfer an array from a PHP file to an external JavaScript file. My approach involves using AJAX as it appears to be the most suitable method for achieving this. However, when I try to use echo json_encode($exif), the JS ...

Developing a custom camera system for a top-down RPG game using Javascript Canvas

What specific question do I have to ask now? My goal is to implement a "viewport" camera effect that will track the player without moving the background I am integrating websocket support and planning to render additional characters on the map - movement ...

Utilizing mustache template strings within the href attribute in VueJS

How can I incorporate a mustache inside an href attribute within the context of Vue.js? After researching various solutions, I attempted to apply them to my code. Mustache inside an href How to pass a value from Vue data to an href? Reddit thread on us ...

Posting values using AJAX in PHP - A guide

test.html <html> <!-- To access the complete PHP-AJAX tutorial, please visit http://www.php-learn-it.com/tutorials/starting_with_php_and_ajax.html If you found this tutorial helpful, a backlink to it would be greatly appreciated. ...

Utilizing angularjs ng-repeat directive to present JSON data in an HTML table

I've been struggling to showcase the JSON data in my HTML table using AngularJS ng-repeat directive. Here's the code snippet: <thead> <tr> <th ng-repeat="(header, value) in gridheader">{{value}}</th> </tr> </ ...

Condensed JQuery condition code for "if" statement

This piece of code is designed to sequentially display 10 questions and control the visibility of each question using the CSS class .hideme. It also sends metrics data to Google Analytics. Although it functions properly, I feel like the code is too leng ...

Equal size images displayed within cards in Material UI

Is there a way to create a list of Material UI components with images that have uniform height, even if the original images vary in size? I want to make all image heights responsive and consistent across all cards. Any suggestions on how to achieve this? ...

Unable to display the complete JSON data using ng-repeat in AngularJS

Utilize ng-repeat to display data retrieved from a web service. Below is my controller JS (GetAllCtrl.js): https://i.stack.imgur.com/GAelG.jpg I have received JSON data: https://i.stack.imgur.com/0xkAU.jpg My goal now is to extract only company informati ...

Is there a problem connecting to the MongoDB server?

I am having trouble connecting to the MongoDB server using the link provided below. I have double-checked the password and dbName, but it still won't connect. Can someone please assist me with this? const mongoose = require('mongoose'); ...

Is it possible to retrieve data from a database using jQuery and store it in separate variables?

I am able to print out one field from a table, but I want to display all fields in separate tables. How can I achieve this? Below is my save/load code: // Save/Load data. $('').ready(function() { if($.cookie('code')) { $.aj ...

Guide to attaching click and keydown events to an input field using Vanilla JavaScript

I am currently working on a project for freecodecamp where I have successfully created a functional example. However, there are a few things that I'm struggling to figure out. Firstly, I need help with executing an AJAX request by either typing in th ...

Chrome on OSX Mavericks threw a RangeError because the maximum call stack size was exceeded

While attempting to run an Angular app using linemanjs in Chrome on a Mac, I encountered the following error: Uncaught RangeError: Maximum call stack size exceeded An interesting observation is that the site functions properly on Chrome on a Windows mach ...

Exploring JavaScript and Node.js: Deciphering the choice of prototype.__proto__ = prototype over using the

Currently exploring the Express framework for node.js and noticed that all the inheritance is achieved through: Collection.prototype.__proto__ = Array.prototype; Wouldn't this be the same as: Collection.prototype = new Array; Additionally: var ap ...

Utilizing Spiderable within Meteor results in the replication of head content before it is presented in the body tags

Having trouble with my meteor site, thought it was Google indexing, now suspecting an issue with the Spiderable package. Meteor version 1.1.0.3 is in use, along with spiderable package and gadicohen:phantomjs as suggested by meteorpedia. The current issu ...

The Vue / Firebase App is experiencing issues with the Modal feature due to a lack of definition for '$'

I encountered the following error: 33:7 error '$' is not defined The code snippet below shows AddToCart.js contents. The modal formatting can be found in my Product List component. <template> <div class="add-to-cart"> ...

Troubleshooting an issue with an AJAX request

Having trouble getting the HTML back from an AJAX call - works in FF but returns "null" in IE when using alert(result.html()); Here's the code, any suggestions? Thanks! The errors variable is also null in IE. It doesn't matter what element I u ...

Creating a fluid side navigation bar in reactjs

Can someone please help me with the following code issue? I am encountering an error related to the script tag when running it in ReactJS, although it works fine in a simple HTML file. Upon starting npm, an error is displayed pointing to line number which ...

What is the process for generating an alert box with protractor?

While conducting tests, I am attempting to trigger an alert pop-up box when transitioning my environment from testing to production while running scripts in Protractor. Can someone assist me with this? ...

Can the selected week be highlighted along with the corresponding week number in a row?

Can we display the number of the week in a row along with the selected week, either in the toolbar or somewhere else? I attempted to utilize ToolbarComponent, but it overrides the entire header. However, I would like to keep it as is and just add informat ...

Changing alert variant dynamically with Vue.js and Bootstrap-Vue

As I work on a vue.js project using bootstrap-vue, I came across the following method to display an alert based on the documentation: <b-alert variant="success" show>Success Alert</b-alert> However, my attempt to achieve this is as follows: ...