Looping over two-dimensional array containing objects in Vue.JS - vue.js

The problem
In Vue, I'm passing an array called issues. The array contains (at present) two objects, but can contain infinite amounts of objects. Every object then has another array named issues, nested inside of it.
The issue is that when I need to display the data, I find that I can't seem to reach the inner "issues" section of it.
I can loop through the first array like so:
<tr v-for="issue in issues" track-by="id">
But that only lets me see the first two objects. I then tried:
<tr v-for="issue in issues" track-by="id">
<td>
<div class="btn-table-align" v-for="issue_title in issue.issues">
#{{ issue_title.title }}
</div>
</td>
</tr>
Which lets me access the sub-elements, but doesn't generate enough rows. I then tried looping over it AGAIN, like so:
<div v-for="first in issues" track-by="id">
<tr v-for="issue in first" track-by="id">
<td>
<div class="btn-table-align">
#{{ issue.id }}
</div>
</td>
</tr>
</div>
But, alas - it generates no rows at all when I do that.
I'd basically need a way to run a "issue in issues", then another for the results and THEIR direct children. The only issue is - I can't figure out how to do it, and Vue won't respond to any of the above attempts! I find a severe lack of documentation on two-dimensional arrays in Vue as well, which has me confused further.
Can anyone shed some light on this? Is it possible, or do I need to adjust the data sent to Vue differently?
To help, I shot an image of an example structure: http://i.imgur.com/6Oz67R9.png

This was a typical 5am question, where I now realize that the data I'm passing makes no sense - it should be the other way around. The actual issues should be in the first array, and the subarray should contain affected servers.

Related

Using computed value in v-for (Vue.js)

I'm currently making bitcoin trading web app (personal project. Not a business one)
I have a bunch of cryptocurrencies prices from API, and showing it all by using v-for loop.
here's part of my code:
<tbody class="text-sm">
<tr v-for="coin in props.coins" :key="coin.code" class="hover:bg-zinc-600">
<td class="p-1">
<div class="font-semibold">{{ coin.name }}</div>
<div class="text-xs text-gray-400">{{ coin.code }}</div>
</td>
<td
class="text-right font-bold align-top p-1"
>{{ Number(coin.trade_price).toLocaleString() }}</td>
<td
:class="{ 'text-blue-400': isNegative(coin.signed_change_rate), 'text-red-400': isPositive(coin.signed_change_rate) }"
class="text-right p-1"
>
<div>{{ Number(coin.signed_change_rate).toFixed(2) }}%</div>
<div class="text-xs">{{ coin.signed_change_price }}</div>
</td>
<td class="text-right align-top p-1">{{ convertTp24h(coin.acc_trade_price_24h) }}</td>
<td class="text-right p-1">
<button class="bg-red-700 rounded-lg hover:bg-red-600 p-1">매수</button>
</td>
</tr>
</tbody>
As you can see I have many methods and expressions that converts raw value from API to human-readables.
I'm wondering if this is a bad practice. I heard that methods are called everytime so, rather use computed().
But as you can see I have my values from API in Object(props.coins) and I'm looping this object in v-for. Can I still use computed() methods to convert a value inside an Object that is also looped by v-for?
You can't use computed for items in a loop, since they don't take in arguments. Computed is used for .. computed properties and methods take in arguments e.g. formatChangeRate()
You are right that methods are called everytime, but that's totally fine and normal practice.
So creating a component with methods like formatChangeRate, formatTradePrice is totally fine.
There are ways to make it work with computed properties but in my opinion its not worth it.
1)
You coould make another component that takes in the item as a prop, uses computed property and displays it in componenent's template but that's a total overhead.
2)
You could map the array and reference it by index. Something like:
computed: {
changeRate() {
this.coins.map(coin => {
return Number(coin.signed_change_rate).toFixed(2) + '%'
})
}
}
Now changeRate is an array of formatted change rates so you could in your v-for do something like
v-for="(coin, index) in coins)">
<td>changeRate[index]</td>
So now you're looping through the array multiple times, and the code is less testable and less readable.
In my opinion using methods is totally fine and the right way to go in this example. The performance of calling a simple formatting method multiple times is negligible.
Also the cache you're refering to is that computed properties are cached based on their reactive dependency. E.g. you have in your data, firstName and lastName. You could then make a computed property called fullName that concats those two. The caching would work so that fullName doesn't change unless firstName or lastName changes.
Since you're looping through an array the value that would be computed is always changing.
you are right, methods are called everytime and in theory thats not really good, but in practice if your method just concat strings or other simple operations, that's really not a big deal. Your computer can do millions of operations like that per seconds.
In the other hand if you do complex operations then the solution is to precalculate before.
After you receive your data construct an Array looking something like bellow and use this one in your template
(pseudo code)
[{
name,
code,
changeRate: Number(signed_change_rate).toFixed(2),
...
},
...
]

Data-Filter Overriding Data-Search Attribute

Using DataTables, I am witnessing a reproduceable issue where the value of the data-filter html attribute is overriding the searchability of the data-search html attribute.
<td data-search="Jared Next" data-order="Jared Next" data-filter="Full-Time DM">
<div class="mb-2">
Jared Next
</div>
<div class="mb-2 text-muted small" title="Number of total deals posted by DM">
Posted: 294
</div>
</td>
When searching by "jared" the row does not appear.
When searching by "full-time dm" the row does appear.
Worth mentioning that the filter works as expected:
I apologize if I've not provided enough code to re-create the issue or if DataTables experts want the whole table.
I can easily provide it all.
The data-search and data-filter attributes are synonyms, in DataTables.
See here for details.
You should use one or the other, but not both at the same time.
Also, from the same doc link as above, in case it is relevant: Make sure the attributes are used consistently for every cell in a column:
In order for the HTML 5 data-* attribute detection and processing to work correctly, all cells in a column must have the same attribute available.

VueJS in IE 11 - template wrapper for <tr> not working, works in Edge and Chrome

This is using Vue 2.5.16 in IE 11. Assume a dataset array in app.data, the following works fine in Chrome (and the code is simplified):
...
<tbody>
<template v-for="(datarow, index) in dataset">
<tr><td> {{ datarow }} {{ index }} </td></tr>
<tr v-if="!(index % 50)"><td> -repeating header row- </td></tr>
</template>
</tbody>
...
However, in IE 11, it does not work and furthermore there is no line and character number in console error (took me some time to figure out). It just says in red:
[object Error] {description: "'datarow' is undefined" ..
It works if I remove the template tag and just put the v-for repeat in first tr and remove the 2nd one.. but I really would like to have the second one.
I assume this is a DOM issue difference in IE 11 and that IE 11 is hoisting the template tag outside the table, but don't know IF any non-standard tag will work, or if so which one will work. How can I solve this?
The solution I found to this problem was to have multiple tbody elements in place vs. template. Multiple tbody tags are allowed in IE 11 without IE moving it out of the table and thus making the tr tag unaware of the referenced loop variables.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tbody
There are two possible side-effects of this:
Your tbody may have been styled by CSS - mine was in bootstrap - so the appearance will be different than expected, normally with extra borders. You'll need to probably use !important or at least your own CSS to overcome this.
At least for IE 11, load time appeared slower, but I have not tested this.
Resulting code:
<table>
<tbody v-for="(datarow, index) in dataset">
<tr><td> {{ datarow }} {{ index }} </td></tr>
<tr v-if="!(index % 50)"><td> -repeating header row- </td></tr>
</tbody>
<tbody>
<!-- not posted above but I used another template/tr for the case of no records found; substituted with just another tbody -->
</tbody>
</table>

Aurelia Possible Memory Leak

I have a table template that is leaking I have pinpointed the code causing the issue to a single line.
<tbody>
<tr repeat.for="row of workListData.rows" click.delegate='resultItemClick($event, row)'>
<td repeat.for="col of workListData.columns">
<template if.bind='col.name === "isChecked"'>
${col.label}
</template>
<template if.bind='col.name !== "isChecked"'>
**${row.Properties[col.name]}**
</template>
</td>
</tr>
</tbody>
${row.Properties[col.name]}
This is the line of code causing the issue this line takes the current row and uses the column name to access the value of the column
enter image description hereOk it seems aurelia is leaking when I have nested repeat.for
Leaks
<tr repeat.for="row of workListData.rows" click.delegate='resultItemClick($event, row)'>
<td repeat.for="col of workListData.columns">
</td>
</tr>
Does not leak
<tr repeat.for="row of workListData.rows" click.delegate='resultItemClick($event, row)'>
</tr>
Its definitely coming from nested repeat problem is if I simplify the code IE remove web services etc its work as expected
One of my colleagues has noticed something interesting commenting out a different template controller also stops the leak seems its not fussy which controller gets commented out.
Finally located the leak it seems I had a couple however one thing for sure is aurelia seems to have a very bad tendency to leak if you do this in a template
${row.Properties[key]}
Not sure if that is supported though
I now instead pass the object and key to a function and return the value which solves the issue

Variables in Handlebars

I'm passing models to a handlebars template and putting a few of the properties in a row. I want to have some sort of position variable for each row. Specifically, I want to know how many rows have been created and have a position associated with each row.
e.g.
{{#each row}}
<span class = (indexHere)>
<tr>
<td> <{{this.property}}>
</tr>
</span>
{{/each}}
This is an old question and maybe at that time Handlebars did not include the #index property, but according to current (1.3.0) documentation:
When looping through items in each, you can optionally reference the current loop index via {{#index}}
You make your own helper :-)
Here's one you can steal:
https://gist.github.com/1048968