As some of you may or may not know the Vue-router 2.3.0 does not handle arrays in GET Query parameters to spec. Let me explain.

When you want to send an array of items to the server, from an array of checkboxes for example, you do some-array[] which translates to some-array[]=2&some-array[]=3 in the URL. Then on the server side of this, in PHP for example, you can do $_POST['some-array'] and this will return an array with [1,2]. Well Vue-router handles things a bit differently.

Prior to 2.0 it used to handle things to spec, now when you pass an array of string items Vue-router just transforms them one by one like so some-array=1&some-array=2 which is bad for a few reasons.

  1. This is not up to spec and handling on the server side is not possible. When trying to access this with PHP you just receive the last some-array item in the URL, which will be 2 in our case.
  2. When there is only one of these parameters: some-array=1 Vue-router will return 1 as a string, because it does not know it should be an array. If there are more than one params, it will return an array of items.

Also if you try to pass an object this get even worse, in the URL we get [Object object]. I along with some other users noted this issue on Github and a potential fix is on its way, but until then, this is what I thought of.

If you just need to handle this on the client, you can make an accessor as a computed property that always returns an array for that parameter:

{
	computed: {
		someArray(){
			const someArray = this.$route.query.someArray
			return Array.isArray(someArray) ? someArray : [someArray]
		}
	}
}

OK so that’s fine and dandy, we now get an array of someArray every time, even if its only one element but accessing the computed property. What about when we refresh our page? What if we want to access this param from the server? Well we cant. As I noted above, we get only the last defined item in the URL. The simplest workaround I managed to think of is using a comma separated list of values.

// Use this because Array.split() on empty string returns [''] which is not what we need atm.
function split (string, sep) {
	const a = string.split(sep)
	if (a[0] === '' && a.length === 1) return []
		return a
}
export default {
	data () {
		return {
			query: {
				someArray: 'first, second, third' // gets transformed into ['first', 'second', 'third'] from the computed prop
			}
		}
	},
	computed: {
		someArray: {
			get () {
				/**
				* our split() function returns a new array from the comma separated list.
				*/
				return split(this.query.someArray, ',')
			},
			set (value) {
				/**
				* Array.toString() returns a comma separated list of array items.
				*/
				this.query.someArray= value.toString() 
			}
		}
	}
}

Now we can even use a v-model in our templates, it will use the computed property`s get to get an array, and its set to transform the array into a comma separated list.

<template>
	<div>
		<h2>Check some values</h2>
		<label v-for="array in someArray">
			<input type="text" name="someArray" :value="array" v-model="someArray"> {{array}}
		</label>
		{{ someArray }}
	</div>
</template>

In the backend you could transform that comma separated string into an array again, with PHP you can do explode(',', $_POST['some-array']).

Here is a webpackbin to demonstrate how it works:

https://www.webpackbin.com/bins/-Kg8kbJX2rIuyrEolj7Y