2

I’m creating a component to display a table based on JSON data, but nothing is shown for my column when the column's property key is lieu.ville. How do I fix this?

Component:

<template>
    <ul class="list-group">
        <li class="list-group-item list-group-item-info">
            <div class="row">
                <div v-for="col in colss" class="" :class="bootstrapClass">{{col | capitalize}}</div>
            </div>
        </li>

        <li v-for="(item,index ) in datas" class="list-group-item" :key="item['id']">
            <div class="row">
                <div v-for="(value,i) in columns" class="" :class="bootstrapClass">
                    <i>{{ item[value] }}</i>
                </div>
            </div>
        </li>
    </ul>

</template>

<script>
var csrf_token = $('meta[name="csrf-token"]').attr('content');

export default {
    props: ['colss','columns','datas','urlajax'],

    computed: {
        bootstrapClass: function() {
            return 'col-sm-' + (12 / this.colss.length );
        },
    },

    mounted: function () {
        console.log("testtttt");
    },

    filters: {
        capitalize: function (str) {
            return str.charAt(0).toUpperCase() + str.slice(1)
        }
    },
}
</script>

Vue bootstrap:

var listSessions = new Vue({
    el: '#listmodalSessions',
    data: {
        // collection des propriétés
        columns: ['id', 'ref_session', 'datesPeriodesConcat','lieu.ville'],
        // collection d'affichage
        colss: ['Id', 'Ref Session', 'Dates','Ville'],
        datas: [],
        urlPrefix:'/admin/User/' ,
    },
    methods: {
        showModal () {
            $('#sessionsModal').modal('show');
        },

        hideModal () {
            $('#sessionsModal').modal('hide');
        },
        // id Item représente l'id du user auquel appartiennent les permissions de la liste
        getDatas(idItem){

            var MonThis = this;
            MonThis.datas = [];

            $.ajax({
                url: this.urlajax,
                cache: false,
                dataType: 'json',
                success: function (data, textStatus, jqXHR) {
                    if (jqXHR.status === 200) {
                        MonThis.datas = data;
                        var index = 0;
                    }
                }
            });
        },

    },
    components: {modalTable},
});

Sample data:

[{
    "id": 6735,
    "formation_id": 8376,
    "statut_session_id": 1,
    "lieu_id": 1,
    "ref_session": "1 333 7020 19S 10 41 01",
    "prixSession": 1385,
    "intraInter": 1,
    "intraInSitu": 0,
    "commentaires": null,
    "created_at": "2019-03-25 17:31:29",
    "updated_at": "2019-03-25 17:31:29",
    "deleted_at": null,
    "periodes": [{
        "id": 5634,
        "session_id": 6735,
        "salle_id": 43,
        "date_debut": "2019-10-07",
        "date_fin": "2019-10-11",
        "commentaires": null,
        "created_at": "2019-03-25 17:31:29",
        "updated_at": "2019-03-25 17:31:29",
        "deleted_at": null
    }],
    "lieu": {
        "id": 1,
        "ville": "Paris",
        "cp": "75",
        "region": null,
        "displaySite": 1,
        "created_at": "2019-03-13 13:24:36",
        "updated_at": "2019-03-13 13:24:36"
    },
    "datesPeriodesConcat": "2019-10-07 au 2019-10-11",
    "lieu2Display": "Paris",
    "link": "<a class=\"btn btn-info\" href=\"\/session\/6735\">Session<\/a>"
}]
tony19
  • 125,647
  • 18
  • 229
  • 307
Eloise85
  • 648
  • 1
  • 6
  • 26

1 Answers1

1

The problem...

item['lieu.ville'] is not the same as item.lieu.ville. The former looks up a property named lieu.ville in item, which doesn't exist in this case. The latter looks up lieu in item, then ville in the result.

One way to solve this is to programmatically split the given object key by . so that the correct property can be resolved:

methods: {
  getValue(item, key) {
    return key.split('.').reduce((obj,k) => obj[k] || {}, item)

    /** The one-liner above is equivalent to the following **/

    const keys = key.split('.')
    for (const k of keys) {
      if (!item) break
      item = item[k]
    }
    return item || {}
  }
},

Suboptimal usage...

You could use that getValue method in your template like this:

<li v-for="item in datas">
  <div class="row">
    <div v-for="key in columns">
      <i>{{ getValue(item, key) }}</i>
    </div>
  </div>
</li>

Edit Resolving prop by method in Vue template

But using such methods in the template is inefficient because the method is called on every render, producing the same result each time.

Something better...

You could use a computed property instead, which gets cached to avoid unnecessary recalculations on render. The computed prop (e.g., named tableData) would contain new table data that has its column's items already resolved:

computed: {
  tableData() {
    return this.datas.map(item => ({
      ...item,
      columns: this.columns.map(key => this.getValue(item, key))
    }))
  }
}

Then, you could use the tableData prop in your template like this:

<li v-for="item in tableData">
  <div class="row">
    <div v-for="value in item.columns">
      <i>{{ value }}</i>
    </div>
  </div>
</li>

Edit Resolving table data in computed prop in Vue template

tony19
  • 125,647
  • 18
  • 229
  • 307