NOTACAT Studio
NOTACAT Studio

Reputation: 217

Computed Conditionals in V-for Vue.js

I'm brand new to vue js and I'm running into a bit of a problem. I have a list of information that I want to print out to the screen. Each item has a type and they're grouped together. Each group should have a header, but not each item. I have a working solution, but it feels like I'm missing something. Example below:

<div id="AnimalList">
    <div v-for="animal in model.Animals">
        <div class="header" v-if="showAnimalHeader(animal.Type)">
            <span>{{animal.Type}}</span>
            <hr/>
        </div>
        <span>{{animal.Type}} <label>Animal Name:</label> {{animal.Name}} <label>Color:</label> {{animal.Color}} </span>
    </div>
</div>

var currentAnimal = '';
    new Vue({
        el: "#AnimalList",
        data() {
            return {
                model: animalModel,
                //currentAnimal: '',
        };
        },
        methods: {
            showAnimalHeader(animal) {
                if (currentAnimal !== animal) {
                    currentAnimal = animal;
                    return true;
                }

                return false;
            }
        }
    });

example data:

{type: dog, name: fido, color: black},
{type: dog, name: lassie, color: white and brown},
{type: cat, name: garfield, color: orange},
{type: cat, name: nermal, color: gray},
{type: fish, name: nemo, color: orange}

I don't like that I'm declaring currentAnimal outside the Vue. It feels like I'm doing this wrong. I tried using the commented data property and this.currentAnimal in the showAnimalHeader method, but then ran into the method firing off hundreds of times (resulting screen was still correct). I feel like I should be using computed instead of a method, but I'm struggling on how to get the correct Animal into the computed prop if that's the right way to do it so I know when the current animal has changed.

Upvotes: 1

Views: 41

Answers (1)

Dan Cress
Dan Cress

Reputation: 11

I think the issue isn't necessarily in the Vue code, but in the data structure. I would move your "type" property into a parent object like so:

animalModel = [
    {
        "type": "dog",
        "items": [
            {
                "name": "fido", 
                "color": "black"
            },
            {
                "name": "lassie", 
                "color": "white and brown"
            }
        ]
    }, {
        "type": "cat",
        "items": [
            {
                "name": "garfield", 
                "color": "orange"
            },
            {
                "name": "nermal", 
                "color": "gray"
            },
        ]
    }, {
        "type": "fish",
        "items": [
            {

                "name": "nemo", 
                "color": "orange"
            }
        ]
    }
]

This would enable you to put a loop inside of a loop in your vue file and achieve the desired result:


<div id="AnimalList">
    <div v-for="animalGroup in model.Animals">
        <div class="benefit-header">
            <span>{{animalGroup.Type}}</span>
            <hr/>
        </div>
        <span v-for="animal in animalGroup.items">{{animal.Type}} <label>Animal Name:</label> {{animal.Name}} <label>Color:</label> {{animal.Color}} </span>
    </div>
</div>

This would remove any need for computed properties or methods for rendering this markup.

You would likely want to update the naming conventions accordingly, but that's how I would handle that dataset. Best of luck. Hope this helps!

Upvotes: 1

Related Questions