/ziggy

Use your Laravel named routes in JavaScript

Primary LanguagePHPMIT LicenseMIT

Ziggy - Use your Laravel named routes in JavaScript

Ziggy – Use your Laravel named routes in JavaScript

GitHub Actions Status Latest Version on Packagist Downloads on Packagist Latest Version on NPM Downloads on NPM

Ziggy creates a Blade directive that you can include in your views. It will export a JavaScript object of your application's named routes, keyed by their names (aliases), as well as a global route() helper function which you can use to access your routes in your JavaScript.

Ziggy supports all versions of Laravel from 5.4 to 7.x.

Contents

Note: you are viewing the develop branch, which is under active development. Not all of the features and changes in this documentation have been released. Docs for the latest Ziggy release, v0.9.4, are in the Readme on the 0.9.x branch.

Installation

  1. Install Ziggy using Composer: composer require tightenco/ziggy.
  2. If using Laravel 5.4, add Tightenco\Ziggy\ZiggyServiceProvider::class to the providers array in your config/app.php.
  3. Include our Blade directive (@routes) somewhere in your template before your main application JavaScript is loaded—likely in the header somewhere.

Ziggy is also available as an NPM package, ziggy-js, that exposes the route() function for use in frontend apps that are not using Blade or Composer. You can install the NPM package with npm install ziggy-js or load it from a CDN:

<!-- Load the Ziggy routes object first -->
<script defer src="https://unpkg.com/ziggy-js@0.9.x/dist/js/route.min.js"></script>

Note that you still have to generate your routes file with php artisan ziggy:generate and make it available to your frontend app.

Usage

This package uses the @routes directive to inject a JavaScript object containing all of your application's routes, keyed by their names. This collection is available at Ziggy.namedRoutes.

The package also creates an optional route() JavaScript helper that functions like Laravel's PHP route() helper, which can be used to retrieve URLs by name and (optionally) parameters.

Examples

Without parameters:

route('posts.index'); // Returns '/posts'

With required parameter:

route('posts.show', { id: 1 }); // Returns '/posts/1'
route('posts.show', [1]); // Returns '/posts/1'
route('posts.show', 1); // Returns '/posts/1'

With multiple required parameters:

route('events.venues.show', { event: 1, venue: 2 }); // Returns '/events/1/venues/2'
route('events.venues.show', [1, 2]); // Returns '/events/1/venues/2'

With query parameters:

route('events.venues.show', { event: 1, venue: 2, page: 5, count: 10 }); // Returns '/events/1/venues/2?page=5&count=10'

If whole objects are passed, Ziggy will automatically look for an id primary key:

let event = { id: 1, name: 'World Series' };
let venue = { id: 2, name: 'Rogers Centre' };

route('events.venues.show', [event, venue]); // Returns '/events/1/venues/2'

Practical AJAX example:

let post = { id: 1, title: 'Ziggy Stardust' };

return axios.get(route('posts.show', post))
    .then((response) => {
        return response.data;
    });

Note: If you are using Axios and making requests that require CSRF verification, use the url() method on the route (documented below). This will ensure that the X-XSRF-TOKEN header is sent with the request.

Default Values

See the Laravel documentation on default route parameter values.

Default values work out of the box for Laravel versions >= 5.5.29, for previous versions you will need to set the default parameters by including this code somewhere in the same page as Ziggy's @routes Blade directive.

Ziggy.defaultParameters = {
    // example
    locale: 'en',
};

Filtering Routes

Filtering routes is completely optional. If you want to pass all of your routes to your JavaScript by default, you can carry on using Ziggy as described above.

Basic Filtering

To take advantage of basic route filtering, you can create a config file in your Laravel app at config/ziggy.php and define either an only or except setting as an array of route name patterns.

Note: You have to choose one or the other. Setting both only and except will disable filtering altogether and simply return the default list of routes.

Example config/ziggy.php:

return [
    // 'only' => ['home', 'api.*'],
    'except' => ['debugbar.*', 'horizon.*', 'admin.*'],
];

As shown in the example above, Ziggy can use asterisks as wildcards in route filter patterns. home will only match the route named home, whereas api.* will match any route whose name begins with api., such as api.posts.index and api.users.show.

Filtering using Groups

You can also optionally define multiple groups of included routes using a groups key in your config/ziggy.php:

return [
    'groups' => [
        'admin' => [
            'admin.*',
            'posts.*',
        ],
        'author' => [
            'posts.*',
        ],
    ],
];

In the above example, we have configured multiple route groups for different user roles. You can expose a specific group by passing the group key into the @routes directive in your Blade view:

@routes('author')

If you want to expose multiple groups you can pass an array of group names:

@routes(['admin', 'author'])

Note: Passing group names to the @routes directive will always take precedence over your other only or except settings.

Content Security Policy

A Content Security Policy may block unsafe inline scripts which Ziggy uses to pass the routes to JavaScript. By adding a nonce to your CSP you can allow certain inlined scripts. To add this nonce to Ziggy you can pass it as the second argument:

@routes(false, '[YOUR_NONCE]')

Or if you are using Spatie's CSP Package:

@routes(false, csp_nonce())

Other Useful Methods

current()

To get the name of the current route based on the browser's window.location, you can use:

route().current();
// returns 'events.index'

To check whether you are currently on a specific route, you can pass the route name to current():

route().current('events.index');
// returns true

You can even use wildcards to check if you're on any of the routes in a given 'group':

route().current('events.*');
// returns true

check()

Ziggy can check if a given named route is defined:

route().check('home');
// returns true if a route name 'home' exists, false otherwise

url()

Ziggy returns a wrapper of the JavaScript String primitive, which behaves exactly like a string in almost all cases. In rare cases, such as when third-party libraries use strict type checking, you may need an actual string literal.

To achieve this you can call url() on your route:

route('home').url();
// returns 'https://ziggy.test/'

Artisan Command

Ziggy registers an Artisan console command to generate a ziggy.js routes file, which can be used as part of an asset pipeline such as Laravel Mix.

You can run php artisan ziggy:generate in your project to generate a static routes file in resources/js/ziggy.js. You can optionally include a second parameter to override the path and file name (you must pass a complete path, including the file name):

php artisan ziggy:generate "resources/foo.js"

Example ziggy.js, where the named routes home and login exist in routes/web.php:

// routes/web.php

Route::get('/', function () {
    return view('welcome');
})->name('home');

Route::get('/login', function () {
    return view('login');
})->name('login');
// ziggy.js

var Ziggy = {
    namedRoutes: {"home":{"uri":"\/","methods":["GET","HEAD"],"domain":null},"login":{"uri":"login","methods":["GET","HEAD"],"domain":null}},
    baseUrl: 'http://ziggy.test/',
    baseProtocol: 'http',
    baseDomain: 'ziggy.test',
    basePort: false
};

export {
    Ziggy
};

Importing the route() helper and generated ziggy.js

// webpack.mix.js
const path = require('path');

mix.webpackConfig({
    resolve: {
        alias: {
            ziggy: path.resolve('vendor/tightenco/ziggy/src/js/route.js'),
        },
    },
});
// app.js

import route from 'ziggy';
import { Ziggy } from './ziggy';

Using with Vue Components

If you want to use the route() helper in a Vue component, add this to your app.js file:

// app.js

import route from 'ziggy';
import { Ziggy } from './ziggy';

Vue.mixin({
    methods: {
        route: (name, params, absolute) => route(name, params, absolute, Ziggy),
    },
});

Then you can use the method in your Vue components like so:

<a class="nav-link" :href="route('home')">Home</a>

Thanks to Archer70 for this solution.

Other

Environment-based loading of minified route helper file

When using the @routes Blade directive, Ziggy will detect the current environment and minify the output if APP_ENV is not local. In this case, ziggy.min.js will be loaded—otherwise, ziggy.js will be used.

Disabling the route() helper

If you only want to use the @routes directive to make your app's routes available in JavaScript, but don't need the route() helper function, you can set skip-route-function to true in your config:

// config/ziggy.php

return [
    'skip-route-function' => true,
];

Contributing

To get started contributing to Ziggy, check out the contribution guide.

Credits

Thanks to Caleb Porzio, Adam Wathan, and Jeffrey Way for help solidifying the idea.

Security

If you discover any security related issues, please email hello@tighten.co instead of using the issue tracker.

License

Ziggy is open source software licensed under the MIT license. See LICENSE.md for more information.