Vue js invalid router after login - javascript

I'm totally new to vue and I've built small vue app in codesandbox:
https://codesandbox.io/s/vue-template-fjd4i
And I have problems with routing, so, how to reproduce it:
click Login and provide any credentials
So now you are on Board page
Click Statistics page
And I get Signup page instead of Statistics, why? I don't understand
I'm using EventBus to refresh navbar after login event-bus.js:
// EventBus.js
import Vue from "vue";
export default new Vue();
When I'm logged (on Board page) and I click on Statistics I can see wrong route in router/index.js beforeEach func:
router.beforeEach((to, from, next) => {
console.log("///////");
console.log(from);
console.log(to);
console.log(next);
console.log("///////");
So i'm getting Signup route in to variable instead of Statistics. Can please anybody help?

This will happen If your route definition uses async loading import(...), and you named the chunks the same. Check the comment that declares the names in your routes.
Also, make sure your Statistics route really does return the correct component. Did you cut-and-paste?

The problem was in <a> tags, don't know why, but kill vue routing, so I changed this:
<router-link v-if="is_logged" tag="li" :to="{ name: 'Statistics' }">
<a>Statistics</a>
</router-link>
to this:
<li v-if="is_logged"><router-link tag="a" :to="{ name: 'Statistics' }">
Statistics
</router-link></li>

Related

Angular routing bug - this.router.navigateByUrl() and this.router.navigate()

I am creating angular application that will handle documentation for my GitHub apps, in more complex way than just readme files. I want to redirect user after clicking in topnav dropdown to selected route, but there's problem with router. (I need to redirect with some parameters, but it doesn't work even with simple path reditect). Those methods redirect to target route for like 1 seconds (like excepted), then user got redirected back to root page.
Code:
/* First element is project name, second is category/part of application name */
choices = ["typing_speed_test", "overview"]
json = json
constructor(private router: Router){}
onProjectClick($event){
this.choices[0] = $event.target.innerHTML.trim();
this.choices[1] = "overview";
this.redirect();
}
onCategoryClick($event){
this.choices[1] = $event.target.innerHTML.trim();
this.redirect();
}
redirect(){
this.router.navigateByUrl("404");
}
Routes:
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'project/:project_name/:category', component: SubpageComponent },
{ path: '404', component: NotFoundComponent },
//{ path: '**', redirectTo: '404', pathMatch: 'full' }
];
Link to gif with problem: https://imgur.com/a/x2mPxvh
Full code in github repo: https://github.com/Dolidodzik/DocsForMyApps (if you used code from here to answer this question, please point that in your answer)
I think I may did some stupid mistake, because I am pretty new in Angular, but I couldn't do it, because every google question showed me solves for ERRORS, when redirect doesn't work at all, not to bugs like in my situation.
You need to remove the href="#" from your anchor links in your navigation bar. It's causing the browser to reload:
<a class="dropdown-item" *ngFor="let item of categories() | keyvalue">
{{item.key}}
</a>
Also this is a bit weird solution:
this.choices[0] = $event.target.innerHTML.trim();
You better just send the item variable in your function call in your template, and you can then read this in your component event handler:
onProjectClick(item){
this.choices[0] = item.key;
this.choices[1] = "overview";
this.redirect();
}
the problem is your lins look like this:
link
default link behavior causes your app reload from the start. you should use [routerLink]="['someUrl']" instead of href. If you need that href in some cases, consider calling $event.preventDefault() to cancel the native browser navigation

Check Firebase onAuthStateChanged before Vue app created in Nuxt JS

I have been using Vue JS v2 for some time now and I'm quite comfortable with it. Recently I have started using Nuxt JS and so far I was able to grasp most of the things. But after spending countless hours of searching the web, I am still unable to find out a way about how to use firebase onAuthStateChanged() before the Vue app gets created in Nuxt JS.
Let me explain a bit
In Vue 2 normally what I do is in main.js file
import Vue from 'vue'
import App from './App.vue'
import { auth } from '#/firebase/init'
let app = null
// ⚡ Wait for firebase auth to init before creating the Vue app
auth.onAuthStateChanged(() => {
// init app if not already created
if (!app) {
app = new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
}
})
But in Nuxt JS the entire main.js file is encapsulated. Now I know that I can use plugin to do stuff like Vue.use() but again those things are happening after the Vue app is created.
I want to wrap the vue app creation inside the firebase auth checking so I see no way to implement this. So, if anyone has any idea about how to implement this then please let me know.
Please note that I am not trying to do any redirection based on the auth state. I know those answers already exist here and I have checked them already.
I had the same problem and found an easier solution. However, I don't why this is not documented anywhere in firebase nuxt...
In the layouts/default.vue Layout I implemented the following:
<template>
<div>
<div v-show="!isLoaded" class="loading">
</div>
<div class="app" id="app" v-if="loaded">
<NavBar :loggedIn="loggedIn" />
<Nuxt id="router-view" />
<Footer />
</div>
</div>
</template>
<script>
export default {
data() {
return {
loggedIn: false,
loaded: false
}
},
created() {
this.$fire.auth.onAuthStateChanged(() => {
this.loaded = true
const user = this.$fire.auth.currentUser;
if (user) {
this.loggedIn = true
}
})
},
...
}
</script>
I think this works exactly like using it in the main.js in vueJS. By using v-if the main app content should only be executed once firebase auth is initialised.
I guess I have a similar problem and I managed to create a login-flow, but it feels like a workaround.
on login I store cookie and user data:
after login via firenbase I save userdata from authUser in vuex store via the onAuthStateChanged hook, which resides in a clientside only plugin.
store firebase token as cookie
on pageReload:
init store on serverside with data from cookie, with nuxtServerInit:
https://github.com/davidroyer/nuxt-ssr-firebase-auth.v2/blob/master/store/index.js
onAuthStateChanged is triggered and does nothing, because the userStore is already initialised
on redirect into app:
if user comes back into my app from payment service provider for example, the vuex store is empty until firebaseAuth plugin loads and saves userdata in vuex store. I use localStorage to persist the public user here, so the app thinks we are still logged in. https://www.npmjs.com/package/nuxt-vuex-localstorage
In the background onAuthStateChanged is triggered. This feels wrong.
Especially in the "on redirect into app" case it would be nice if onAuthStateChanged is handled first, because then we could skip localStorage and use access userData from firestore fore example without having to wait for the authPlugin to come up.
Maybe a solution could be to write a module, which offers more hooks you can use:
https://nuxtjs.org/guide/modules/#run-tasks-on-specific-hooks

Getting data from independent child component to other components with router

I'm fairly new to Vue, which is why I can't ignore my feeling that I'm doing something wrong.
I have an independent component inside a view component, which has to emit data to other components.
The project has the following components: App, Navbar, Home, Statistics, Table and Search.
The Search component is used inside the Home component. It contains an <input> to let the user input his account name.
The Table component is used inside the Statistics component. It shows a table based on the input from the Search component.
+-- App
| +-- Navbar
| +-- Home
| +-- ---- Search
| +-- Statistics
| +-- ---- Table
My main App.vue contains the router-view:
<template>
<div id="app">
<Navbar></Navbar>
<div class="container">
<router-view></router-view>
</div>
</div>
</template>
Two of them are main view components, which have a fixed route: Home & Statistics.
The routes (router.js) are the following:
export default new Router({
routes: [{
path: '/',
name: 'home',
component: Home
},
{
path: '/statistics',
name: 'statistics',
component: Statistics
}
]
})
The Navbar component contains the router-links to the view components:
<template>
<div id="navbar">
<nav>
<ul>
<li class="active"><router-link to="/">Home</router-link></li>
<li><router-link to="/statistics">Statistics</router-link></li>
</ul>
</nav>
</div>
</template>
Now: What is the right way to get the data from the independent child component Search to my other independent child component Table?
The logical way would be Search-> Home -> App -> Statistics -> Table.
I already tried to use an event bus with $emit and $on, but it seems like the data can't connect to each other with the router inbetween.
Right now, I have a const in my main.js to store this global user data:
export const store = new Vue({
data: {
username: ''
}
})
which I import everywhere I need it, but I highly doubt that this is the right way to do it.
I also thought about using props for my Table component, but I would need to pass my data from App to Statistics to Table which would work, but feels like a lot of boilerplate. Also: I need to get the username to the App before I can do that anyways, which is what I don't know how to do proberly.
Thanks in advance.
It's OK to use a global store as you are doing, the docs even have a guide on how to do so: https://v2.vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch
If you want a more structured way of doing this, look into Vuex, which is also written by the Vue team: https://vuex.vuejs.org/
Vuex integrates nicely into the Vue devtools and sidesteps the import/passing problems you're describing (because it is a plugin injected via Vue.use, then $store is available in every Vue)

Vue with dynamic routes and components

Trying to build a test app to see if Vue is a suitable replacment for our AngularJS app. Trying to learn Vue at the same time.
After the user logs in we fetch some roles for that user. Base off those roles is how the menu gets built.
User1 { Role1, Role2, Role3}
In theory
User2 {Role1, Role3}
So Role1 would have a path of /start/page1 and page1 (component) and two child components.
Same with Role2 path of /start/page2 and page2 would have components on it.
I don't really want to build the routes until I know which roles the user has.
I'm using quasar-framework.org and using the menu slide out. Trying to create a menu on the fly. Seems like I need the components to already be imported?
I'm able to build the menu by looping through the roles and setting up a list of menus.
Trying to build the routes on the fly using this.$router.addRoutes(newRoute);
To do that I need the component to already be imported.
The Quasar way is load the components on the fly I guess.
In router.js
function loadPage (component) {
return () => import(`../../pages/${component}.vue`)
}
I can't seem to use that function in a method section.
Is this possible in Vue?
Take a look at vue-router lazy loading documentation and Quasar lazy loading documentation
You can't do it in a method, but if the user permission don't match the route permissions the component is never loaded, which is basically what you want.
Example
const routes = [
{
path: '/some-page-protected',
component: () => import('pages/SomePage'),
meta: {role: 'admin'}
}
]
Or
const SomePage = () => ('pages/SomePage')
const routes = [
{
path: '/some-page-protected',
component: SomePage,
meta: {role: 'admin'}
}
]

vuejs router-link not working in lazy loading routes

I am setting my router follow this guide
https://router.vuejs.org/en/advanced/lazy-loading.html
const PageWaitingRoom= () => import(/* webpackChunkName: "group-CCManageBusiness" */'./../pages/customer-care/manage-business/PageWaitingRoom');
const Routes = [
{
path: '/customer-care/manage-business/waiting-room',
component: PageWaitingRoom,
name: PageWaitingRoom.name
}
]
And in another page, I use router-link like this:
<router-link class="nav-link text-uppercase"
:to="{name: 'PageWaitingRoom'}"
exact>
Waiting Room
</router-link>
Everything work fine until I use webpack to make production build with UglifyJsPlugin, the router-link not resolve the url, it always point to root url instead. I must change the router-link to not use the name like this:
<router-link class="nav-link text-uppercase"
to="/customer-care/manage-business/waiting-room"
exact>
Waiting Room
</router-link>
But I don't want to do by that way, I refer to use component name in the router-link, since it is shortly and easy to me to change the url in the future.
This problem is only happen when I use UglifyJsPlugin, I am not sure what I am missing.
Anyone are facing this problem like me? Please give me advice.
Thanks!
If you want you preferred version to work you need to disable mangling, like so:
new webpack.optimize.UglifyJsPlugin({
mangle: false
})
This should stop it messing with your route name but note that this also stops the obfuscation of the code. You can do a Google search to decide whether this is a problem or not. Some people say yes, others no.
I have disabled this option in my latest app with the reasoning that if someone is determined enough, renaming PageWaitingRoom to xyz isn't going to stop them, only slow them down.
Actually I did not named the route by a string, but I used the name of the component as the route name instead, like below, and it makes my stupid poblem lol:
const Routes = [
{
path: '/customer-care/manage-business/waiting-room',
component: PageWaitingRoom,
name: PageWaitingRoom.name //<-- UglifyJsPlugin will do its business and cause the route issue.
//name: 'PageWaitingRoom' <-- Should use this
}
]

Categories

Resources