I'm trying to figure out how to make a loop work inside another loop in Vue. The task seems trivial when working with React, but in View I don't understand how I can use a standard hook when working with arrays inside a template/JSX.
By condition, the input data comes from the server in the given format. At the moment, the code in the attached snippet below does not work due to syntax errors.
Can you help me fix errors in the snippet? This will help me understand how to correctly apply a loop in a loop in a template relative to Vue...
const timeStamp = moment(new Date());
var app = new Vue({
el: "#app",
template: "#app-template",
data: {
symbols: [
{
id: 1,
name: "EURUSD",
candles: [
{
timeStamp: timeStamp.subtract(1, "days").format("YYYY-MM-DD"), // Yesterday
open: 1.1,
close: 1.2,
high: 1.3,
low: 1.0,
},
{
timeStamp: timeStamp.format("YYYY-MM-DD"), // Today
open: 1.2,
close: 1.5,
high: 1.6,
low: 1.2,
}
]
},
{
id: 2,
name: "USDRUB",
history: [
{
timeStamp: timeStamp.subtract(1, "days").format("YYYY-MM-DD"), // Yesterday
open: 75,
close: 76,
high: 77,
low: 73,
},
{
timeStamp: timeStamp.subtract(1, "days").format("YYYY-MM-DD"), // Today
open: 76,
close: 77,
high: 79,
low: 75,
}
]
}
]
}
});
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script type="text/x-template" id="app-template">
<table>
<thead>
<tr>
<th>Symbol</th>
<th>Change</th>
<th>Time stamp</th>
</tr>
</thead>
<tbody>
<tr v-for="(symbol, index) in symbols" :key="index">
{
symbol.candles.map(candle => {
const { name } = symbol
const { open } = candle.history[0]
const { close, timeStamp } = candle.history[1]
const change = Number.parseFloat((100 / (open / (close - open)))).toFixed(2)
return (
<td>{{ name }}</td>
<td>{{ change }} %</td>
<td>{{ timeStamp }}</td>
)
})
}
</tr>
</tbody>
</tabel>
</script>
You are missing the closing </table>
tag, first of all (you have a typo: </tabel>
).
Also, I would recommend an approach like this:
<tr v-for="(symbol, index) in symbols" :key="index">
<template v-for="candle in symbol.candles">
<td>{{ symbol.name }}</td>
<td>{{ getChange(candle) }} %</td>
<td>{{ candle.history[1].timeStamp }}</td>
</template>
</tr>
...
methods: {
getChange(candle) {
const { open } = candle.history[0];
const { close } = candle.history[1];
return Number.parseFloat((100 / (open / (close - open)))).toFixed(2);
}
}
The <template>
tag can be used in cases like this, where you want to repeat a block of code without adding an extra parent tag around it (as <template>
does not render as an actual HTML tag).
The reason I suggest moving the logic outside of the template and into a method is that Vue only supports one expression per data binding (source: https://v2.vuejs.org/v2/guide/syntax.html#Using-JavaScript-Expressions).