Kieran_st's avatar

Vue Composition and Ziggy

So I'm making a website using Vue 3 (Composition API), InertiaJS, Laravel. As such, Ziggy is being used to allow Vue to access the Laravel routes. artisan ziggy:generate is used to create the routes file

So far, using route('my.named.route') in the <template> area works perfectly.

However, when I try to use route in the <script setup> area, even inside a function, I get route is not a function

I have a feeling this is something to do with the setup flag and whatnot, but I'm honestly not sure exactly what the cause is nor how to solve it. I've not been able to find anything in searches about it either, every search comes up with people who can't get Ziggy working at all, which is not my issue.

My app.js file looks like:

import {createApp, h} from "vue";
import {createInertiaApp, Head, Link} from "@inertiajs/vue3";
import {resolvePageComponent} from "laravel-vite-plugin/inertia-helpers";

import {Ziggy} from './ziggy';
import {ZiggyVue} from "ziggy-js/dist/vue.es";

import GeneralLayout from "./template/Layout.vue";
import DashboardLayout from "./template/DashboardLayout.vue";

import FontAwesomeIcon from "./fontawesome";
import './bootstrap';

createInertiaApp({
  resolve: async (name) => {
    let page = await resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue'));
    if (page.default.layout === undefined) {
      if (name.startsWith('Admin/')) {
        page.default.layout = (h, page) => h(DashboardLayout, () => page);
      } else if (name.startsWith('Business')) {
        page.default.layout = (h, page) => h(GeneralLayout, () => page);
      } else {
        page.default.layout = (h, page) => h(GeneralLayout, () => page);
      }
    }
    return page;
  },
  setup({el, App, props, plugin}) {
    const app = createApp({render: () => h(App, props)})
      .use(plugin)
      .use(ZiggyVue, Ziggy)
      .component("Link", Link)
      .component("Head", Head)
      .component("font-awesome-icon", FontAwesomeIcon);
    app.mount(el)
  },
  title: title => `MySite - ${title}`,
});

My main view looks like:

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- Fonts -->
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link
    href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,500;0,600;0,700;1,500;1,600;1,700&display=swap"
    rel="stylesheet">
  @inertiaHead
  @vite(['resources/css/app.css', 'resources/js/app.js'])
  @env('local')
    {{--  Adds a toolbar at the bottom of the page summarising clockwork data  --}}
    <script src="https://cdn.jsdelivr.net/gh/underground-works/clockwork-browser@1/dist/toolbar.js"></script>
    {{-- Provides client-side metrics to clockwork --}}
    <script src="https://cdn.jsdelivr.net/gh/underground-works/clockwork-browser@1/dist/metrics.js"></script>
  @endenv
</head>
<body class="antialiased">
@inertia
</body>
</html>

Thanks in advance for any assistance, and let me know if any more information is needed :)

0 likes
8 replies
LaryAI's avatar
Level 58

The issue you're facing is that the route function is not available in the <script setup> area. This is because the <script setup> block is meant for setting up variables and functions that are accessible in the template area, but not in the script area.

To solve this, you can create a separate function outside of the <script setup> block that uses the route function and then call that function from within the <script setup> block.

Here's an example of how you can do this:

import { ref } from 'vue';

// Create a function that uses the route function
function getRoute() {
  return route('my.named.route');
}

export default {
  setup() {
    // Call the getRoute function and store the result in a ref
    const routeRef = ref(getRoute());

    // Use the routeRef in your template
    return {
      route: routeRef,
    };
  },
};

In your template, you can then access the route variable like this:

<template>
  <div>
    <p>{{ route }}</p>
  </div>
</template>

This way, you can use the route function in the <script setup> area by calling the separate function that has access to it.

Kieran_st's avatar

Except the code block by the AI response doesn't use <script setup> and its talking about accessing the route in the <template>.

The part about the script setup for setup I believe is part of the issue - I'm just not sure how to solve it

Pretty neat feature for the forums to have an AI reply :D - not quite the solution though I don't think :(

Kieran_st's avatar

Thanks for the snippet and link - never thought of looking at that area of the docs since it mentions its for projects managed separately from the backend (which mine is not). However good to know about the additional parameters in the route function :)

Tried your suggestion from the snippet and results are: Page no longer renders and throws this error in console - Uncaught (in promise) TypeError: o2.t.routes is undefined when I add the following to my .vue component:

// File: resources/js/Pages/Admin/User/index.vue
import route from 'ziggy-js'; // error caused by the import. ziggy-js is installed
import {Ziggy} from "../../../ziggy";

// ...

// The function has more than this, I've just stripped it back to this for testing and debugging
const submit = () => {
	router.post(route('my.route'), {some: data.value}, undefined, Ziggy)
}
MohamedTammam's avatar

@Kieran_st You're adding the ( in wrong place. I think that what you meant:

router.post(route('my.route', {some: data.value}, undefined, Ziggy))
1 like
Kieran_st's avatar

@MohamedTammam Ah whoops, I do indeed! Thanks for catching that. router.post(route('my.route', undefined, undefined, Ziggy), {some: data.value})

Still getting the same errors - route is not defined without the import route and o2.t.routes is undefined with the import. Currently doing some googling on the new error to see if I can find anything, but so far no luck.

Kieran_st's avatar
Kieran_st
OP
Best Answer
Level 9

Ah, got it working.

Seems I just had to add @routes to the main blade view in the head. (Hadn't done so as I thought the vue plugin for ziggy handled things, but obviously the setup script tag runs prior to a lot of functions being available) Now it works in the <script setup> area :)

1 like

Please or to participate in this conversation.