0

I have a vue component that displays a list of items. I can flag any item as "active" (boolean value). That value is saved to a database.

For example, I could have five total items. Three of them could be marked as "active" the remaining two are not.

When my page loads, the active/not active data is coming from my controller and I am passing data to my vue component as a property. The property has an attribute active that can be toggled on/off. That value is stored in a database as a boolean.

This is what my component looks like:

<template>
    <div class="item" :class="{'active' : isActive}" @click="handleClick($event, item)">
        <div v-if="item.icon" class="item-icon">
            <i :class="item.icon"></i>
        </div>
        <div class="item-title">
            {{ item.title }}
        </div>
    </div>
</template>

<script>
    export default {
        name: 'Item',
        data() {
            return {
                isActive: false,
            }
        },
        methods: {
            async handleClick(event, item) {
                try {
                    let response = await axios.patch(`/path/${item.id}`, {
                        title: item.title,
                        active: !this.isActive,
                    });

                    if (response.status === 200) {
                        this.isActive = !this.isActive;
                        console.log('isActive: ', this.isActive);
                    } else {
                        console.error('Error: could not update item. ', response);
                    }
                } catch (error) {
                    console.error('Error: sending patch request. ', error);
                }
            },
        },
        props: {
            item: {
                type: Object,
                required: true,
            },
        },
    }
</script>

Overall, the system is working. My request(s) are getting handled correctly and data is getting updated correctly.

If I change my template to this:

<div class="item" :class="{'active' : isActive}"
     @click="handleItemClick($event, item)">

I am seeing the class/ui update correctly. But, because the initial data is coming from Laravel (controller) I need to have the two classes.

So somehow I am not binding to the classes correctly so that when I click, the ui is getting updated correctly.

EDIT

Thank you so much for your suggestions. I updated my component logic to reflect what is working properly. When things fall apart is when I change the template to account for if an item is already active:

<div class="item" :class="{'active' : isActive, 'active': item.active}"
     @click="handleClick($event, item)">

The logic still works (when I refresh the page) but the UI doesn't update dynamically.

1
  • 1
    :class="{ active: isActive || item.active }" perhaps? Commented Oct 16, 2019 at 22:02

2 Answers 2

2

You can setup a computed property that accounts for the item.active and for isActive in your component, like:

computed: {
  bindActive() {
    return this.isActive || this.item.active;
  }
}

So you can setup only one class in your template syntax:

<div class="item" :class="{'active' : bindActive}"  @click="handleItemClick($event, item)">...</div>
Sign up to request clarification or add additional context in comments.

5 Comments

yeah, I'm so use to the class api :-/
Only thing that comes to mind is if item comes from a loop, eg v-for="item in items". If so, OP won't be able to use a computed property
Thank you so much! I think this is close. The issue I believe I am struggling with is that I can't set isActive: false, for everything. Since the item could be already active, by setting the data attribute to false, vue thinks everything is inactive by default. Is there such a thing as dynamically setting the data attribute?
Well, you can change the isActive variable at any time -- in fact you do it in your code. You want it to be active by default, and switch to false only and only if the item (when it comes from the api call) has active as false?
Correct. If the item comes back as active from the api, then I need to set isActive to false. But, if another item comes back from the api as (not active), then I need to set isActive to true. When my page loads, the vue component is getting populated from a controller - which has all the data (active or not) for each item.
0

First I want to thank everyone for their suggestions; it was a tremendous help!

I hope that I can help others with this so here is what I came up with.

<template>
    <div class="item" :class="{'active': isActive}"
         @click="handleClick($event, item)">
        <div v-if="item.icon" class="item-icon">
            <i :class="item.icon"></i>
        </div>
        <div class="item-title">
            {{ item.title }}
        </div>
    </div>
</template>

<script>
    export default {
        name: 'Item',
        data() {
            return {
                isActive: this.item.active,  // <-- this was my error
            }
        },
        methods: {
            async handleClick(event, item) {
                try {
                    let response = await axios.patch(`/path/${item.id}`, {
                        title: item.title,
                        active: !this.isActive,
                    });

                    if (response.status === 200) {
                        this.isActive = response.data.item.active;
                    } else {
                        console.error('Error: could not update item. ', response);
                    }
                } catch (error) {
                    console.error('Error: sending patch request. ', error);
                }
            },
        },
        props: {
            item: {
                type: Object,
                required: true,
            },
        },
    }

Hope this helps someone!

Comments

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.