Ayeye Brazo
Ayeye Brazo

Reputation: 3476

Nuxt open link into modal

I'm building a Nuxt application that has a list of products and clicking on one of them open a dedicated page of the product. It is working fine.

Structure is:

/pages/featured // directory of products
/pages/product/:id/:slug // Dedicated product page

Now I wish to add a new feature:

A nice example of what I wish to achieve is the photo directory of Youpic.

A list of "products", visible entirely in a dialog with its internal navigation.

I'm looking at the various nuxt-routing and vue-router documentations to try developing it but I'm still far away from the solution.

This small portion of the code I see here looks pretty similar at what I need but I don't understand how should I correctly implement it and how to create my nuxt custom routing:

export default {
  router: {
    extendRoutes (routes, resolve) {
      routes.push({
        path: '/users/:id',
        components: {
          default: resolve(__dirname, 'pages/users'), // or routes[index].component
          modal: resolve(__dirname, 'components/modal.vue')
        },
        chunkNames: {
          modal: 'components/modal'
        }
      })
    }
  }
}

Upvotes: 11

Views: 10598

Answers (3)

ajobi
ajobi

Reputation: 3116

I have built a sandbox solution for you here: https://codesandbox.io/s/reverent-leftpad-xj81p

Explaining the solution:

The solution uses beforeRouteLeave() function from the vue-router which is available to your nuxt pages by default:

beforeRouteLeave(to, from, next) {
  if (to.name === "product-id") {
    this.displayProductModal(to);
  } else {
    next();
  }
},

This function interrupts any route changes on the featured page before they happen, and if the target route is the route of the product detail (which means someone clicked on product link), it opens the modal dialog instead.

To handle the url change on opening and closing of the modal, the window.history object is used:

displayProductModal(route) {
  this.activeModal = route.params.id
  window.history.pushState({}, null, route.path)
},
hideProductModal() {
  this.activeModal = null
  window.history.pushState({}, null, this.$route.path)
}

Try to play around a bit, it should work exactly like the youpic example you provided.

Note: There are no real "modals" used in the example, the whole example is as basic as possible for the sake of simplicity.

Upvotes: 23

Hardik Shah
Hardik Shah

Reputation: 1456

What I have an understanding of your requirement is looking at https://youpic.com/explore is that you want https://www.example.com/featured (directory of products) route and there on click of product you want open dialog which will be full screen with the route as https://www.example.com/product/:id/:slug (Details page).

please correct me if I am wrong!!

Now you can achieve this with 2 way

1) On click of the each product(i.e.https://www.example.com/featured (directory of products) route) use nuxt-link with redirect to https://www.example.com/product/:id/:slug (Details page) route

2) On click of the each product(i.e.https://www.example.com/featured (directory of products) route) manually update the route with router.push and open dialog

Now, if we see https://youpic.com/explore and let's take this as Nuxt code structure will be pages/explore where they manually update route with router.push to https://youpic.com/image/16660875/steffi-by-fs22photography but when you share/take this URL(https://youpic.com/image/16660875/steffi-by-fs22photography) and try to open that so in Nuxt code structure you have to maintain pages/image/:id/:slug which will actually a page if you directly see go to https://youpic.com/image/16660875/steffi-by-fs22photography Page you can see.

Hope this will help you!!

If you have any doubts we can discuss more!!

Upvotes: 1

retrograde
retrograde

Reputation: 2979

I recently implemented this feature after facing nearly the same situation you are in. At least in my case, I was really overthinking it.

All that I did was take the single resource page (/pages/product/:id/:slug in your case) and have it be a modal by default. I am using vuetify and v-dialog is a modal. The nuxt project hierarchy didn't change. Your equivalent would be the slug.vue page.

<template>
<v-dialog v-model="drawer" fullscreen hide-overlay transition="dialog-bottom-transition">
    <v-card height="100vh">
        <div class="flex">
            <v-toolbar dark color="primary darken-2">
                <v-btn icon dark @click="close">
                    <v-icon>close</v-icon>
                </v-btn>
                <v-toolbar-title>{{member.alias}}</v-toolbar-title>
                <v-spacer></v-spacer>
                <v-toolbar-items>
                    <v-btn text nuxt :to="`/members/${member.id}/notes`">Notes</v-btn>
                    <v-btn text nuxt :to="`/members/${member.id}/edit`">Edit</v-btn>
                    <v-btn text nuxt :to="`/members/${member.id}/payments`">Payments</v-btn>

                </v-toolbar-items>
            </v-toolbar>
            <v-row no-gutters>
            </v-row>
        </div>
    </v-card>
</v-dialog>
</template>

<script>
import { mapGetters } from "vuex";
export default {
watchQuery: ["id"],
transition(to, from) {
    if (!from) {
        return "slide-left";
    }
    return +to.query.id < +from.query.id ? "slide-right" : "slide-left";
},
data() {
    return {
        id: this.$route.params.id,
        drawer: true
    };
},
fetch({ store, params }) {
    store.commit("members/active", params.id);
},
computed: {
    member: {
        get() {
            return this.$store.getters["members/active"];
        },
        set(member) {
            this.$store.commit("members/update", {
                id: member.id,
                member: member
            });
        }
    }
},
methods: {
    async close() {
        await this.$nuxt.$router.go(-1);
        this.drawer = false;
    }
}
};

Upvotes: 1

Related Questions