I am kind of stumped on this one. I would like to pass an object to another function when I click on a button. That way I can work with the object in the final function.
In this example, I would like to pass the car object from the renderCar function to the makeEditable function when I click on the Edit button.
What I tried:
<button onclick="makeEditable(${car})">Edit</button>
<button onclick="makeEditable(car)">Edit</button>
<button onclick="makeEditable('${car}')">Edit</button>
I can pass in a string like
<button onclick="makeEditable('${car.type}')">Edit</button>
but no success with passing the whole object.
Here I wrote up an example of what I am looking to do.
Fiddle: https://jsfiddle.net/kyleteeter/v8gs05e1/10/
HTML
<div id="root" ></div>
JS
let cars = [
{
"color": "purple",
"type": "minivan",
"capacity": 7
},
{
"color": "red",
"type": "station wagon",
"capacity": 5
}
]
cars.map(car => {
this.root.innerHTML = this.renderCar(car)
});
function renderCar(car) {
return `<div><div data-type="color">${car.color}</div><div data-type="type">${car.type}</div><div data-type="capacity">${car.capacity}</div><button onclick="makeEditable('${car}')">Edit</button></div>`
}
function makeEditable(car){
console.log(car)
}
CodePudding user response:
I think you can create a document fragment or just an element and attach the event listeners to it. This way you will have more agility passing any type of argument.
However, if you really want to make it work the way you have tried then consider the example below.
I'd say implementation of it is overkill but it works.
Basically, any parameter passed this way will be converted to a string(because it is wrapped with quotes). To take advantage of it you can stringify your object and encode it base64(to keep it as string), and in target function just decode&parse it the same way.
const cars = [
{
color: 'purple',
type: 'minivan',
capacity: 7,
},
{
color: 'red',
type: 'station wagon',
capacity: 5,
},
];
cars.forEach((car) => {
this.root.innerHTML = renderCar(car);
});
function makeEditable(car) {
const parsed = JSON.parse(atob(car));
console.log(parsed);
}
function renderCar(car) {
const stringified = btoa(JSON.stringify(car));
return `
<div>
<div data-type='color'>${car.color}</div>
<div data-type='type'>${car.type}</div>
<div data-type='capacity'>${car.capacity}</div>
<button onclick="makeEditable('${stringified}')">Edit</button>
</div>
`;
}
<div id="root"></div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
The problem becomes pretty evident if you look at the generated HTML. In it, you'll have '[object Object]'
just because that's what happens if you try to convert an object into a string, and it's kind of obvious that from this point you can't call makeEditable()
and expect the object to magically appear back - you end up calling the function with '[object Object]'
as an argument and, well, this isn't the object you're looking for.
I'm seeing two possible approaches:
- Try to shove the entire object into the HTML like so:
function renderCar(car) {
return `<div><div data-type="color">${car.color}</div><div data-type="type">${car.type}</div><div data-type="capacity">${car.capacity}</div><button onclick="makeEditable('${encodeURI(JSON.stringify(car))}')">Edit</button></div>`;
}
... then, to properly retrieve it, you'd have to reverse the process in the makeEditable()
function:
function makeEditable(data) {
let car = JSON.parse(decodeURI(data));
console.log(car);
}
... but that's kind of ugly and might not always work.
- Store some unique IDs with the data and only pass that into the HTML, then use it to do a lookup on the array:
let cars = [
{
color: "purple",
type: "minivan",
capacity: 7,
id: "2a93d4e1-9ee9-4490-b4a8-da836cf81d7f",
},
{
color: "red",
type: "station wagon",
capacity: 5,
id: "aa207e90-08d1-434f-afeb-aed1dbd1dab9",
}
];
cars.map((car) => {
this.root.innerHTML = this.renderCar(car);
});
function renderCar(car) {
return `<div><div data-type="color">${car.color}</div><div data-type="type">${car.type}</div><div data-type="capacity">${car.capacity}</div><button onclick="makeEditable('${car.id}')">Edit</button></div>`;
}
function findById(id, array) {
return array.find((e) => e.id === id);
}
function makeEditable(id) {
let car = findById(id, cars);
console.log(car);
}