dominotrix
dominotrix

Reputation: 367

Change specific values of an array dynamically

I have a string like this inside a textarea with id #map_coords.

[id:1,x:288.43,y:260.15,url:#]-[id:2,x:396.43,y:310.15,url:#]-[id:3,x:503.43,y:299.15,url:#]-[id:4,x:642.43,y:191.15,url:#]

I assign the string to a variable: var getVals = jQuery('#map_coords').val();

I am converting the string to array: getVals = getVals.split("-");

So now the above string looks like this:

Array
0: [id:1,x:288.43,y:260.15,url:#]
1: [id:2,x:396.43,y:310.15,url:#]
2: [id:3,x:503.43,y:299.15,url:#]
3: [id:4,x:642.43,y:191.15,url:#]

Then, with a click of a button, I want to delete a value inside the array, let's say the 2nd one (1:). I do that with this:

getVals.splice((getMap - 1),1);

The getMap variable is always the same value as the id: inside the array. So if I need to delete the id:2 I will splice the 1 value (that's why I do getMap - 1 ).

After the deletion, the array looks like this:

Array
0: [id:1,x:288.43,y:260.15,url:#]
1: [id:3,x:503.43,y:299.15,url:#]
2: [id:4,x:642.43,y:191.15,url:#]

Which is good, but the problem is that now the 1: key, has an id:3 which is wrong. I want to change that to id:2. Same goes for the id:4 that needs to change to id:3 and so on for every key inside the array AFTER the id:2. And this id:2 is not static but dynamically changes depending on the getMap variable. To do this, I convert once again the key into another array. Like this:

var arrLength = getVals.length;
for (var i = (getMap - 1); i < arrLength; i++) {
  var newVals = getVals[i].split(",");
}

The magic happens inside the for arguements, where I set the var i = (getMap - 1). This helps me do changes to the values that proceed the key I changed.

Now we get to split each key and the results for the are these:

0: [id:3
1: x:503.43
2: y:299.15
3: url:#]

and this:

0: [id:4
1: x:642.43
2: y:191.15
3: url:#]

Great! Now I can simply change only the [0] key and substract 1 from their values, making 3 into 2 and 4 into 3 and so on until the array ends. I do it like this:

var arrLength = getVals.length;
for (var i = (getMap - 1); i < arrLength; i++) {
  var newVals = getVals[i].split(",");
  for (var x = 0; x < 1; x++) {
    newVals = newVals[0].replace((i+2),(i+1));
  }
}

If I do console.log(newVals) I get the correct changed values:

[id:2
[id:3

Yes! It worked but... now, how do I put these new values back to the original getVals array? The final form that I need to get is this:

[id:1,x:288.43,y:260.15,url:#]-[id:2,x:503.43,y:299.15,url:#]-[id:3,x:642.43,y:191.15,url:#]

It's the same string you saw at the start of this post only that the id:2 key is now deleted and all the following keys have their id:'s substracted by 1.

Finally I will do: getVals.toString().replace( /],/g,']-'); which helps me add the - symbol in-between the arrays and convert the whole thing into a string again and pass it as a value inside the textarea where it came from!

So my only problem is how can I update the results of newVals inside my getVals array?

Thanks so much if you read all of this!

Upvotes: 0

Views: 769

Answers (2)

NikoKyriakid
NikoKyriakid

Reputation: 630

What if you disregard the id completely from the object/item and populate when needed just using the index of that item in the array.

I will give you an example code here and in https://codesandbox.io/s/great-hopper-3eb4y

Sorry for using ES6, you can easily transform it to not use class, and import.

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div id="app">
      <textarea id="txt-area" rows="10" cols="50"></textarea>
      <br /><br />
      <input id="add-input" placeholder="use this format: x,y,url" />
      <button id="add-button">Add</button>
      <br /><br />
      <input
        type="number"
        id="remove-input"
        placeholder="use numbers: 0,1,2,3"
      />
      <button id="remove-button">Remove</button>
    </div>

    <script src="src/index.js"></script>
  </body>
</html>

MyMemory.js

class MyMemory {
  constructor() {
    this.value = [];
  }

  setInitialState(str) {
    this.value = str.split("-").map((x, i) => {
      const groups = /\[id:(\d*),x:(\d*.\d*),y:(\d*.\d*),url:(.*)\]/.exec(x);
      return {
        x: groups[2],
        y: groups[3],
        url: groups[4]
      };
    });
  }

  add(inputArray) {
    this.value.push({
      x: inputArray[0] || "#",
      y: inputArray[1] || "#",
      url: inputArray[2] || "#"
    });
  }

  getText() {
    return this.value.map((v, i) => MyMemory.objToString(v, i)).join("-");
  }

  remove(id) {
    id = Number.parseInt(id);

    if (id >= 1 && id <= this.value.length) {
      this.value.splice(id - 1, 1);
    } else {
      console.error("Remove id is not valid. Use a number, please!");
    }
  }

  static objToString(obj, idx) {
    const { x, y, url } = obj;
    return `[id:${idx + 1}, x:${x}, y:${y}, url:${url}]`;
  }
}

export default MyMemory;

index.js

import $ from "jquery";
import MyMemory from "./MyMemory";
import "./styles.css";
// window.$ = $;

const memory = new MyMemory();

const initialState =
  "[id:1,x:288.43,y:260.15,url:#]-[id:2,x:396.43,y:310.15,url:#]-[id:3,x:503.43,y:299.15,url:#]-[id:4,x:642.43,y:191.15,url:#]";

const bindEvents = () => {
  const $txtArea = $("#txt-area"),
    $add = $("#add-button"),
    $remove = $("#remove-button"),
    $add_input = $("#add-input"),
    $remove_input = $("#remove-input");

  memory.setInitialState(initialState);
  $txtArea.val(memory.getText());

  $add.on("click", (e) => {
    const newVal = $add_input.val();
    const ar = newVal && newVal.split(",");
    memory.add(ar);
    $txtArea.val(memory.getText());
  });

  $remove.on("click", (e) => {
    const id = $remove_input.val();
    memory.remove(id);
    $txtArea.val(memory.getText());
  });
};

$(document).ready(bindEvents);

Upvotes: 0

mplungjan
mplungjan

Reputation: 177702

I strongy suggest you paste JSON into the textarea

Here I do simple replacing to get a proper object - this is all unnecessary if you have a proper JSON string to begin with

let  str = document.querySelector("#t1").value;
// replace to make a proper JSON 
str = "["+str
  .replaceAll("#",'"#"}')
  .replaceAll("-",",")
  .replaceAll("x",'"x"')
  .replaceAll("y",'"y"')
  .replaceAll("id",'{"id"')
  .replaceAll("url",'"url"')
  +"]"
let getVals = JSON.parse(str).flat()
document.querySelector("#t2").value = JSON.stringify(getVals)
const getMap = 3;
getVals.splice((getMap - 1),1);
getVals.forEach((item,i) => item.id=i+1)
document.querySelector("#t3").value = JSON.stringify(getVals)
This is what I read<br/>
<textarea id="t1" rows=5 cols=50>
[id:1,x:288.43,y:260.15,url:#]-[id:2,x:396.43,y:310.15,url:#]-[id:3,x:503.43,y:299.15,url:#]-[id:4,x:642.43,y:191.15,url:#]
</textarea>
<hr>
This is what I generate <br/>
<textarea id="t2" rows=5 cols=50>
</textarea>
<hr>
After deleting and renumbering<br/>
<textarea id="t3" rows=5 cols=50>
</textarea>

Upvotes: 1

Related Questions