4

What I Have

I'm generating a table based on a 2D array in Vue2. I can get the table to display fine with all the values in the right spots but I'm having trouble with the formatting. The template looks something like this:

<table>
  <thead>
    <tr>
      <th>Title</th>
      <th>Column 1</th>
      <th>Column 2</th>
    </tr>
  </thead>
  <tbody>
    <tr v-for="row in data">
      <td>{{row[0]}}</td>
      <td>{{row[3]+row[1]+row[4]}}</td>
      <td>{{row[3]+row[2]+row[4]}}</td>
    </tr>
  </tbody>
</table>

And the data looks something like this:

var data = [
  ['revenue', 123.4, 153.48, '$'],
  ['cost', 93.26, 109.48, '$'],
  ['profit', 30.14, 44, '$'],
  ['margin', 24.425, 28.668, '', '%']
];

What I Failed

This works... ish. I can have whatever rows I want and I can specify the units—prefixed or suffixed—but it isn't perfect. The biggest issue is that currency has different numbers of decimal places. I could store those values as strings, but some of them are reused in calculations which means I would have to parse them.

What I Tried

It was at this point that I came across filters. Since this project that I've inherited already has a bunch built in, it seems they will do exactly what I want. I can just change it to {{row[1] | currency}} and it spits it out all nicely formatted. The only problem is that I have mixed data types. In the example, revenue, cost, and profit are all currency values, but margin is a percentage.

Ideally I would like to specify the filter in the 4th index of each array:

var data = [
  ['revenue', 123.4, 153.48, 'currency'],
  ['cost', 93.26, 109.48, 'currency'],
  ['profit', 30.14, 44, 'currency'],
  ['margin', 24.425, 28.668, 'percent']
];

and then use something like this to spit out the values:

<td>{{row[1] | row[3]}}</td>
<td>{{row[2] | row[3]}}</td>

However, this doesn't seem to work. I also tried filters[row[3]] and a bunch of other variations but it seems like the syntax for that doesn't exist. I can of course write my own functions for formatting and then use something like this.formatters[row[3]](row[1]), but it doesn't make a lot of sense to re-implement something that already exists. If there's a way to access the filters' underlying functions without making it too messy I could do that but it doesn't seem ideal.

What I Want

The ideal solution would be a way to use the existing filters to format the output all within the table. Calling the functions on the values directly would also be okay. Failing that, I could pre-format the values and store them as strings in a separate object, using the existing functions, but that isn't ideal.

0

3 Answers 3

5

This will allow you to keep your data format and use existing filters.

new Vue({
  el:"#app",
  data:{
    data: [
      ['revenue', 123.4, 153.48, "currency"],
      ['cost', 93.26, 109.48, "currency"],
      ['profit', 30.14, 44, "currency"],
      ['margin', 24.425, 28.668,  "percent"]
    ]
  },
  methods:{
    format(value, filter){
      return Vue.filter(filter)(value)
    }
  }
})

Template

  <tr v-for="row in data">
    <td>{{row[0]}}</td>
    <td>{{format(row[1], row[3])}}</td>
    <td>{{format(row[1], row[3])}}</td>
  </tr>

Example.

Sign up to request clarification or add additional context in comments.

2 Comments

This is what I'm looking for. Vue.filter(filter)(value) is the piece I was missing to make the workaround nice and clean.
@3ocene Yeah, Vue.filter() with just the name of the filter returns the filter itself. vuejs.org/v2/api/#Vue-filter
1

The documentation on Vue filters is lacking, but you apparently cannot access filters dynamically like you are wanting to do.

Your best option is to keep your formatting functions in an object like you suggest.

You could make it a little cleaner by adding a catchall filter to your component and pass the type as a parameter:

filters: {
  format(value, type) {
    return this.formatters[type](value);
  }
}

Then in your template:

<td>{{row[2] | format(row[3]) }}</td>

2 Comments

This is a good answer. I would go with this, but the Vue.filter(filter)(value) call in @Bert Evan's answer is just a little cleaner IMO.
Yeah, I wasn't aware of that. That's definitely the way to go if you want to use the formatters as filters themselves. You could also return Vue.filter(type)(value) with my answer if you wanted. Just depends on how you want to write it out in the template.
-4

Use

{{row[2] | rowFilter(row[3])}} 

And create own filter

3 Comments

This answer doesn't really explain anything. You should probably add more details, perhaps an example, and justification for why I should do exactly what I said I didn't want to do.
This is exactly what you need, I didn't know you never created a filter before. it's the same tip as other 2 answers, except the part where you create your own filter.
I don't need to write a filter and this is not "exactly what I need". I specifically said, "I can of course write my own functions for formatting and then use something like this.formatters[row[3]](row[1]), but it doesn't make a lot of sense to re-implement something that already exists". You just told me I should re-implement the functions in a new filter. More importantly, the other answers provide a reasoning rather than just telling me to do something. That is the type of content that belongs on SO, not small snippets of code with no explanation or reasoning.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.