alanbuchanan
alanbuchanan

Reputation: 4173

Vue multi-purpose components?

I have a small app that lets you add, remove and edit recipes to a list of recipes.

Adding has the route /add and editing has the route /edit. I am using a component called AddRecipe for both routes.

The component simply behaves slightly differently if the route contains 'edit' - i.e. the input fields are pre-populated with the values you are editing.

Here is AddRecipeForm.vue, the shared component:

<template>
    <div>
        <form class="form">
            <input v-model="recipe.name" placeholder="Recipe Name">
            <textarea v-model="recipe.description" placeholder="Recipe Description..." rows="10"></textarea>
            <button :disabled="nothingEntered()" @click.prevent="addRecipe">Submit</button>
        </form>
    </div>
</template>

<script>
export default {
    name: 'AddRecipeForm',
    data() {
        return {
            recipe: this.isEdit() 
            ? this.$store.state.recipes[this.$route.params.id]
            : {
                name: '',
                description: ''
            }
        }
    },
    methods: {
        isEdit() {
            return this.$route.path.includes('edit')
        },
        addRecipe() {
            if (this.isEdit()) {
                this.$store.dispatch('addRecipe', this.recipe)
            } else {
                this.$store.dispatch('addRecipe', {
                    id: Date.now(), 
                    ...this.recipe
                })
            }
            this.$router.push('/')
        },
        nothingEntered() {
            return !this.recipe.name || !this.recipe.description
        }
    },
}
</script>

I am thinking there are better solutions to this issue. For example what if there are more views that are required later in the project that also require the component? I can't keep checking the route in the component if I want a nice clean readable reusable component.

What is your preferred way of dealing with routes that require the same view?

Upvotes: 2

Views: 74

Answers (2)

JJPandari
JJPandari

Reputation: 3522

One common technique when getting too many ifs is to use a configuration map (I made this phrase up), e.g.

data() {
    return {
        configMap: {
            add: {
                addRecipe: function () {},
                inputDisabled: false
            },
            edit: {
                addRecipe: function () {},
                inputDisabled: false
            },
            view: {
                addRecipe: function () {},
                inputDisabled: true
            }
        }
    }
}

here we map the condition, which is a segment of the route path, to options we can use directly in this component, so we can then write in template :disabled=configMap[routeType].inputDisabled.

And in vue, we can place inputDisabled in computed, addRecipe in methods to declare them more clearly, just like you did above.

And if the type of add, edit go beyond routes, we can define the type as a prop and pass it in (as a config option, just like we would any other reusable component)

Upvotes: 1

Saurabh
Saurabh

Reputation: 73649

If you look at it from single responsibility, which state if you have 2 reasons to change for a class(component in your case), you have to split the functionality in two classes. than it may seem like a overloaded component.

However, given current simpliciity of logic involved, It seems a nice solution till you can wrap the logic inside a function like isEdit but if there are more different type of checks coming into picture, you can create two or multiple separate components like AddRecipeForm/EditRecipeForm etc each doing single thing.

Upvotes: 0

Related Questions