简体   繁体   中英

Vue Component Conditional Creation

I want to create a list of actions (each of which is a component) conditionally if the object variable store.plan is not empty, I have tried v-if which works well for rendering but not for creating the component.

I get an error:

Uncaught (in promise) TypeError: action is undefined

The full code of this component can be found here .

Can you please tell me how can I handle this problem? thanks in advance.

呃

<template>
    <div class="planlist" v-if="parse">
        <ul id="planOl">
        <Action
        v-for="action in store.plan"
            :action_id="action.act_id"
            :actor="action.actor"
            :color="action.color"
            :size="action.size"
            :lego_name="action.lego"
            :pick_pos="action.pick"
            :place_pos="action.place"
            :blocked="action.blocked"
            :status="action.status"
            :key="action.act_id"
        />
        </ul>
    </div>
</template>

<script>
import Action from '../components/Action.vue';
import { store } from '../js/store.js'

export default {
    name: 'Plan', 
    data() {
        return {           
            store,
        }
    },
    computed: {
        parse() { 
            if (store.plan.length > 0) { 
                return true;
            }
            return false;
        }
    },
    components: {Action}
}
</script>

Did you try with optional chaining :

parse() { 
  return store?.plan?.length > 0 ? true : false
}

and don't mix v-if and v-for. Try to create wrapper div with v-if around your component:

<ul id="planOl">
  <div v-if="parse">
    <Action
    v-for="action in store.plan"
        :action_id="action.act_id"
        :actor="action.actor"
        :color="action.color"
        :size="action.size"
        :lego_name="action.lego"
        :pick_pos="action.pick"
        :place_pos="action.place"
        :blocked="action.blocked"
        :status="action.status"
        :key="action.act_id"
    />
  </div>
</ul>

It is recommended not to use v-if and v-for directives together on the same element due to the syntax ambiguity.

As per your code, Computed property parse is used to check the length of an array. You can move the v-if to a container element (eg ul ).

In template :

<ul id="planOl" v-if="parse">
 <Action v-for="action in store.plan">...</Action>
</ul>

Script :

computed: {
    parse() { 
        return store.plan.length > 0 ? true : false;
    }
}
  1. To make the process easy, we can move the store.plan to a computed property to use inside the template and parse property.
  2. Simply return store.plan.length from the computed property will do the job too instead of returning true and false based on condition.
  3. If you want to use v-if just outside the Action component, you can use template to do this. No need for an extra element.

So, below changes can help fixing the issues-

<template>
    <div class="planlist">
        <ul id="planOl">
            <template v-if="parse">
                <Action
                    v-for="action in plan"
                    :key="action.act_id"
                    :action_id="action.act_id"
                    :actor="action.actor"
                    :color="action.color"
                    :size="action.size"
                    :lego_name="action.lego"
                    :pick_pos="action.pick"
                    :place_pos="action.place"
                    :blocked="action.blocked"
                    :status="action.status"
                />
            </template>
        </ul>
    </div>
</template>

<script>
import Action from "../components/Action.vue";
import { store } from "../js/store.js";

export default {
    name: "Plan",

    components: {
        Action,
    },

    computed: {
        // A computed property to access the plan ()
        plan() {
            return store.plan;
        },

        parse() {
            /**
             * 1. The plan should be available (not null or empty or undefined)
             * 2. The plan should be an array so length property can be applied
             * 3. If its an array then it should have data (length in other words)
             */
            return this.plan && Array.isArray(this.plan) && this.plan.length;
        },
    },
};
</script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM