VueJS - updating URL with dynamic data - vuejs2

I have a single page VueJS app with a number of data variables I want to encode into the URL.
As an example if my route configuration is (I'm not sure if the syntax is correct):
routes: [
{
path: '/:foo/:bar/:oof/:rab',
component: App
}
And the Component is:
<script>
export default {
name: "App",
data: function() {
return {
foo: 1,
bar: 2,
oof: 3,
rab: 4
}
}
}
Then the URL would be http://www.example.com/#/1/2/3/4
And if foo is changed to 9999 the URL would automatically update: http://www.example.com/#/9999/2/3/4
It would also respond to the user changing the URL, or opening the app with a different URL by loading the URL values into the data.
I thought this would be relatively straightforward but after a Google I'm utterly confused by the correct way of going about this.
Any help/ examples/ solutions greatly appreciated.

Whatever you use to change the values would need to trigger a route push. For example
methods: {
changeFoo (newFoo) {
// you can set foo but it probably won't matter because you're navigating away
this.foo = newFoo
this.$router.push(`/${newFoo}/${this.bar}/${this.oof}/${this.rab}`)
}
See https://router.vuejs.org/guide/essentials/navigation.html
It might be easier if you name your route, eg
routes: [{
name: 'home',
path: '/:foo/:bar/:oof/:rab',
component: App
}]
then you could use something like
this.$router.push({name: 'home', params: this.$data})

It seems that there are two things you're trying to achieve, but I'm not sure from your example which comes first in your ideal order of operations:
Getting the values from your URL
This can be achieved through this.$route.params, which will be an object containing the values you're looking for.
Setting the URL based on your foo, bar, oof, rab variables
You can use this.$router.push() to do this: vue-router docs

Related

Choose which component to show on certain route in Vue.js

Is it possible to set a condition in a route to decide which component to show in it? Something like this:
let someBoolean = true;
const routes = [
{ path: '/foo', component: someBoolean ? Foo : Baz },
{ path: '/bar', component: Bar }
]
And boolean value can be changed. Depending on that component should also be chosen.
According to Codesandbox, it is possible.
However, the routes tree is built at the app startup, so if you change the variable through an action from your app, nothing should happen, the tree shouldn't be built again.
EDIT:
Vue Router has an API that allows you to update your tree after the tree was built.
You have Router.addRoute(), and this trick that allows you to reset the tree to its initial state and conditionally add the route you want to keep.

(vue router) Is there a neat way to not duplicate code when creating two routes with an almost identical view?

I have a NewArticleView vue component that is mapped to /articles/new, like this:
const routes = [
...
{
path: '/articles/new',
name: 'New Article',
component: NewArticleView
},
...
]
The view is basically just a form.
I want to create an EditArticleView component but it feels wrong making a new component, since it will be almost identical to NewArticleView.
I really wish there was a way to send an edit flag or something when navigating to the route (something like router.push('/articles/new', editArticle=true)), which modifies the behaviour of the component. Like binding form values to the article I want to edit, instead of an empty form, and use an update api call instead of the one used for creating a new article.
Is there a neat way to do this?
You could make one component like ArticleView which accepts a prop named editArticle :
{
path: '/articles/new',
name: 'ArticleView',
component: NewArticleView,
props: route => ({ editArticle: route.query.editArticle})
},
then use it like /articles/new?editArticle=true

How to pass route parameters as numbers?

In the section Passing Props to Route Components of Vue documentation, they explain how to pass a parameter from the location path into the component, and they declare the props as an array. But in the Style guide, they mention it is preferable to have props define (at least) their data type.
If i were to listen to the style guide, and if i wanted my URL to define id's of the entities they want to refer to (for example /user/99), then how would i pass that parameter as a number, and avoid the console error telling me it expected a number, but got a string? There are no examples of this.
In the line { path: '/user/:id', component: User, props: true }, i would need some extra parameters specifying that id is of type Numeric. But how exactly?
You can create a function that returns props. This allows you to cast
parameters into other types, combine static values with route-based
values, etc.
Reference.
const router = new VueRouter({
routes: [
{
path: '/user/:id',
component: User,
props: route => ({ id: Number(route.params.id) }),
},
],
})

How to understand vue router navigation?

I am working with this piece of code:
<script>
import router from '../router'
export default {
name: 'Page2',
data () {
return {
id: 0,
msg: 'Hey Nic Raboy'
}
},
created() {
this.id = this.$route.params.id;
},
methods: {
navigate() {
router.go(-1);
}
}
}
</script>
This is printed on the second page Template B if you will but I am confused on the navigate portion. Specifically this:
navigate() {
router.go(-1);
}
I have not worked with VueJS router before, can anyone please explain what this code section does?
Vue-router package works in the same way with the HTML5 History mode as it stated in the vue-router documentation
This method takes a single integer as parameter that indicates by how
many steps to go forwards or go backwards in the history stack,
similar to window.history.go(n).
So basically this is what you should expect from router.go()
// go back by one record, the same as history.back()
router.go(-1)
You can also learn more about HTML5 History mode from here
Have a look at the router.go(n) documentation in the section on programmatic navigation. The example explains that n can be positive or negative and indicates the number of steps in the browser's history to move.
// go forward by one record, the same as history.forward()
router.go(1)
// go back by one record, the same as history.back()
router.go(-1)
So router.go(-1) is the equivalent of hitting the "back" button in your browser.

explain vue-router component as a function

I have seen in several different places the following type of route definition:
{ path : '/dashboard',
component: { render (c) { return c('router-view') }},
children:[{
path:"",
component: Dashboard
}]
},
I am trying to understand how this is different then
{ path : '/dashboard',
component: Dashboard
},
I think it is related to the optional addition of child routs (e.g. /dashboard/user) so that and the children array here just explains that the Dashboard component renders the path /dashboard whereas if I had the second piece of code then it can only render /dashboard.
What I do want to know is what exactly this does
component: { render (c) { return c('router-view') }},
I assume this is some form of a degenerated component but I don't understand what exactly does it do and how.
In Vue, a component is created using an object containing its configuration.
The simplest possible component may look something like this
componentConfig = {
template: '<div>test</div>'
};
Vue.component('test', componentConfig);
In some cases, a developer might not want to use template, and would want to create element from scratch using pure Javascript. That's where render function comes in.
Vue recommends using templates to build your HTML in the vast majority
of cases. There are situations however, where you really need the full
programmatic power of JavaScript. That’s where you can use the render
function, a closer-to-the-compiler alternative to templates.
from https://v2.vuejs.org/v2/guide/render-function.html#Basics
To change the example above to using render function:
componentConfig = {
render: function(createElement) {
return createElement('div', 'test')
}
};
Vue.component('test', componentConfig);
They would produce the exact same result:
https://codepen.io/jacobgoh101/pen/ZoKwKb?editors=1010
https://codepen.io/jacobgoh101/pen/PemVmy?editors=1010
In other words, render function is simply an alternative to using template.
{
component: {
render(c) {
return c('router-view')
}
}
}
is equal to
{
component: {
render(createElement) {
return createElement('router-view')
}
}
}
is equal to
{
component: {
template: `<router-view></router-view>`
}
}
Because render function is closer-to-the-compiler, it's faster compared to using template. That's probably why the author of your code does it this way.
I don't know the rest of your code, but it looks like this might be an implementation of the vue-router Lazy Loading functionality. Basically, Vue + Webpack are going to split your code into chunks and only load those chunks whenever the user attempts to navigate to those routes, rather than loading them all and creating a bigger bundle to download than necessary.
When building apps with a bundler, the JavaScript bundle can become quite large, and thus affect the page load time. It would be more efficient if we can split each route's components into a separate chunk, and only load them when the route is visited.
Combining Vue's async component feature and webpack's code splitting feature, it's trivially easy to lazy-load route components.