Vue Component not rendering when clicking v-btn with route assigned - vue.js

I am having trouble getting a component to load.
I have a Navbar with a Drawer with routes to each main page of my web app.
So far I have been able to make a page titled "Weapons.vue" which shows a list of weapon Categories in a video game ( such as Sniper Rifles and Handguns ). I use the "data()" to pass in names, images, and routes. Clicking on one of these weapons category v-btn brings me to a page which displays weapons within a category. In this question, I will be talking about "Assault-rifles.vue".
The issue I am having is that I am able to get to the Assault-Rifles.vue page whenever I click the v-tn with the assigned routes, but when I try to do the same thing within the Assault-rifles.vue page , by using v-btn and specified routes to get to a specific weapon , will bring me to an empty component. The path I specified shows in the URL, but it isn't displaying my "ADAR.vue" component ( ADAR is a type of weapon in the game ).
Here is my App.vue
<template>
<v-app>
<Navbar />
<v-content class="mt-5--grey mx-5--grey black">
<router-view></router-view>
</v-content>
</v-app>
</template>
<script>
import Navbar from "#/components/Navbar";
export default {
name: "App",
components: { Navbar },
data: () => ({
//
})
};
</script>
Here is my Weapons.vue (where the user should start). Didn't add all the data in the data() to save space.
<template>
<div class="mx-5 mb-5">
<h1 class="green--text ma-5">Weapons</h1>
<v-container class="my-5">
<v-layout row wrap>
<v-flex xs12 s6 m4 lg3 v-for="weapon in WeaponCat" :key="weapon.weapontype">
<v-card class="text-md-center ma-3 grey darken-4">
<v-responsive class="pt-4">
<v-img contain :src="weapon.images"></v-img>
</v-responsive>
<v-card-title class="justify-center">
<div class="heading font-weight-black white--text">{{ weapon.WeaponType}}</div>
</v-card-title>
<v-card-actions class="justify-center">
<v-btn flat class="green black--text ma-3" :to="weapon.route">View Weapons</v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-container>
</div>
</template>
<script>
export default {
data() {
return {
WeaponCat: [
{
WeaponType: "Assault Rifles",
images: "/WeaponCatimages/AR.png",
route: "/weapons/Assault-Rifles"
},
.....
]
};
}
};
</script>
Here is my Assault Rifles Category pages ( Assault-Rifles.vue ). Again removed some data to save space.
<template>
<div class="mx-4 Armor">
<h1 class="green--text ma-5">Assault Rifles</h1>
<v-container class="my-5">
<v-layout row wrap>
<v-flex xs12 s6 m4 lg3 v-for="weapon in Weapon" :key="weapon.weapon">
<v-card class="text-md-center ma-3 grey darken-4">
<v-responsive class="pt-4">
<v-img contain :src="weapon.images"></v-img>
</v-responsive>
<v-card-title class="justify-center">
<div class="heading font-weight-black white--text">{{ weapon.Weapon}}</div>
</v-card-title>
<v-card-actions class="justify-center">
<v-btn flat class="green black--text ma-3" :to="weapon.route">View Stats</v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-container>
</div>
</template>
<script>
export default {
data() {
return {
Weapon: [
{
Weapon: "ADAR",
images: "/WeaponIMG/AR/ADAR_2-15.png",
route: "/weapons/Assault-Rifles/ADAR"
},
....
]
};
}
};
</script>
Here is my "ADAR.vue" component ( the one that wont render ).
<template>
<div class="mx-4 ADAR">
<h1 class="white--text">ADAR</h1>
</div>
</template>
<script>
export default {};
</script>
Here is my route.js . It is super long so i removed some things...
import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";
import Weapons from "./views/Weapons.vue";
import AssaultRifles from "./views/AssaultRifles.vue";
import ADAR from "./views/ADAR.vue";
Vue.use(Router);
export default new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/",
name: "home",
component: Home
},
{
path: "/armor",
name: "armor",
component: Armor
},
{
path: "/weapons",
name: "weapons",
component: Weapons
},
{
path: "/weapons/Assault-Rifles",
name: "Assault Rifles",
component: AssaultRifles
},
{
path: "/Weapons/Assault-Rilfes/ADAR",
name: "ADAR",
component: ADAR
},
]
});
I have tried and tried multiple things such as changing if "/" appears and capitalization and I just cant seem to find the answer anywhere. I would love some help on this please.

Your route path says /Weapons/Assault-Rilfes/ADAR, note the misspell Rilfes.
Also you might want to use lowercase for the whole URL, it looks neater imo.

Related

How to get the right content to be displayed with buttons? (Vue/vuetify)

I'm trying to use v-if and v-show to display the contents of two different pages. If you click on button A, the table for page A is displayed, and if you click on button B, the table for page B is displayed. But with the code I have now, both pages are displayed when clicking on button B. How can I get the right page depending on the button that is clicked? I'm thinking of using v-if/else but I'm not sure how.
My code:
<template>
<v-main>
<v-row align="center" justify="space-around">
<v-col class="text-center" cols="10" sm="7">
<v-btn v-on:click="first= !first">View first table</v-btn>
<p v-show="first"><FirstTable/></p>
<v-btn v-on:click="second= !second">View second table</v-btn>
<p v-show="second"><SecondTable/></p>
</v-col>
</v-row>
</v-main>
</template>
<script>
import FirstTable from '#/pages/main-page/FirstTable'
import SecondTable from '#/pages/main-page/SecondTable'
export default {
name: 'MainPage',
components: {
FirstTable,
SecondTable
},
data() {
return {
first: false,
second: false
}
},
}
This is because you are not setting first to false again. anyway heres a way of doing it.
<template>
<v-main>
<v-row align="center" justify="space-around">
<v-col class="text-center" cols="10" sm="7">
<v-btn #click="toggleTable('first')">View first table</v-btn>
<FirstTable v-if="activeTable === 'first'"/>
<v-btn #click="toggleTable('second')">View second table</v-btn>
<SecondTable v-if="activeTable === 'second'"/>
</v-col>
</v-row>
</v-main>
</template>
<script>
import FirstTable from '#/pages/main-page/FirstTable'
import SecondTable from '#/pages/main-page/SecondTable'
export default {
name: 'MainPage',
components: {
FirstTable,
SecondTable
},
data() {
return {
activeTable: null,
}
},
methods: {
toggleTable(val) {
this.activeTable = val;
}
},
};

vue-router not rendering component, but changing url on this.$router.push

I'm trying to redirect to a Menu after pressing a button, I have followed this tutorial
but it's not working,
When Pressing my button the url updates, but stays in the same view, it's also adding /#/ to my url instead of following what I coded in routes.js
I'm getting the next error on console
Uncaught (in promise)
NavigationDuplicated {
_name: "NavigationDuplicated",
name: "NavigationDuplicated",
message: "Navigating to current location ("/menu") is not allowed", stack:
When pressing the button the url turns into http://localhost:8080/#/menu instead of
http://localhost:8080/menu
If I manually type the url http://localhost:8080/menu turns into this
http://localhost:8080/menu/#/
Please help, I'm fairly new to vuejs
This is the structure of my project
main.js
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import vuetify from './plugins/vuetify'
import routes from './routes'
import 'roboto-fontface/css/roboto/roboto-fontface.css'
import '#mdi/font/css/materialdesignicons.css'
Vue.config.productionTip = false
Vue.use(VueRouter)
const router = new VueRouter({routes});
new Vue({
render: h => h(App),
router,
vuetify
}).$mount('#app')
App.vue
<template>
<div id="app">
<Home/>
</div>
</template>
<script>
import Home from './views/Home.vue'
import 'material-design-icons-iconfont/dist/material-design-icons.css';
export default {
name: 'App',
components: {
Home
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
my routes.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'
import TraceabilityMenu from './views/TraceabilityMenu.vue'
Vue.use(VueRouter)
const routes = [
{ path: '/', component: Home, name: 'home' },
{ path: '/menu', component: TraceabilityMenu, name: 'traceability-menu' },
{path: '/about', component: About, name: 'about'}
]
export default routes;
My Home.vue which is the first view to load(by the App.vue)
<template>
<v-app id="inspire">
<v-app-bar app color="indigo" dark>
<v-toolbar-title>Project Traceability</v-toolbar-title>
<template>
<v-spacer />
<v-btn color="primary" #click="showPopupLogin()" :to="{ name: 'login'}" >Ingresar</v-btn>
</template>
</v-app-bar>
<PopupLogin v-show="showLogin"/>
<v-content>
<v-container
class="fill-height"
fluid
>
<v-row
align="center"
justify="center"
>
<v-col class="text-center">
</v-col>
</v-row>
</v-container>
</v-content>
<v-footer
color="indigo"
app
>
</v-footer>
</v-app>
</template>
<script>
import PopupLogin from '#/components/PopupLogin.vue';
export default {
props: {
source: String,
},
data: () => ({
showLogin : false
}),
components: {
PopupLogin,
},
methods: {
showPopupLogin() {
this.showLogin = !this.showLogin
}
}
}
</script>
The component PopupLogin
<template>
<v-app id="inspire">
<v-content>
<v-container class="fill-height" fluid>
<v-row align="center" justify="center">
<v-col cols="12" sm="8" md="4">
<v-card class="elevation-12">
<v-toolbar color="primary" dark flat >
<v-toolbar-title>Iniciar sesión</v-toolbar-title>
<v-spacer />
<v-tooltip bottom>
</v-tooltip>
</v-toolbar>
<v-card-text>
<!-- Formulario de login-->
<v-form v-model="validForm" ref="formLogin">
<v-text-field
required
label="Usuario"
:rules="nameRules"
name="login"
type="text"
v-model="existingUser.username"/>
<v-text-field
required
id="password"
prepend-icon="lock"
label="Contraseña"
name="password"
type="password"
v-model="existingUser.password"/>
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer/>
<v-btn color="primary" #click="loginUser()">Ingresar</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container>
</v-content>
</v-app>
</template>
<script>
export default {
name: 'PopupLogin',
props: {
source: String
},
data: () => ({
validForm : false,
//objetos
existingUser : {}
}),
methods: {
//Funcion que llamara al servicio de login en backend
loginUser() {
this.$router.push({path: '/menu'});
}
}
}
</script>
TraceabilityMenu.vue the view which I'm trying to render after the press of the button Login
<template>
<v-app id="inspire">
<div>RENDER ME!</div>
</v-app>
</template>
<script>
export default {
props: {
source: String,
},
data: () => ({
drawer: null,
}),
}
</script>
On your main.js file try changing
const router = new VueRouter({routes});
to
const router = new VueRouter({routes, mode: 'history'});
Edit: Also check if you have included the router-view tag on your root component App.vue.

Render Component in loop, use Index in method of child component (VueJS)

I have two components where some exchange of props takes place. Props is the whole todo array, which is updated by a click on the button with the "addTodo" method. Passing the array down to the child works fine. I can display the props dynamically in my p-tags, but it seems to be not possible to use it my the methods of my child component.
<template>
<v-app>
<v-content>
<h2>Add a Todo</h2>
<v-col cols="12" sm="6" md="3">
<v-text-field label="Regular" v-model="text"></v-text-field>
</v-col>
<div class="my-3">
<v-btn medium #click="addTodo">Add Todo</v-btn>
</div>
<div v-for="(todo, index) in todos" v-bind:key="index">
<HelloWorld
v-bind:todos="todos"
v-bind:index="index"
v-bind:class="(todos[index].done)?'green':'red'"
/>
</div>
</v-content>
</v-app>
</template>
<script>
import HelloWorld from "./components/ToDo.vue";
export default {
components: {
HelloWorld
},
data: function() {
return {
text: "",
todos: []
};
},
methods: {
addTodo() {
this.todos.push({
text: this.text,
done: false
});
}
}
};
</script>
This is my child component
<template>
<v-card max-width="250">
<v-card-text>
<h2 class="text-center">{{todos[index].text}}</h2>
<p class="display-1 text--primary"></p>
<p>{{index}}</p>
</v-card-text>
<v-card-actions>
<v-btn text color="deep-purple accent-4" #click="done"></v-btn>
<v-btn text color="orange accent-4">Delete Task</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
export default {
props: ["todos", "index"],
methods: {
done() {
this.todos[1].text = "bla";
}
}
};
</script>
<style scoped>
.seperator {
display: flex;
justify-content: space-between;
}
</style>
I pass a whole array with objects as props, and using the index inside the p-tag works fine, but I also want to use it like this:
methods: {
done() {
this.todos[index].text = "bla";
}
}
'index' is not defined
Everything works fine, but I am not able use the index value inside the method. What am I doing wrong here?
The way you write it out, there is nothing in scope defining index. Where is that value coming from?
Index is a prop and so it must be referenced with this.
done () {
this.todos[this.index].text = 'bla'
}

Vuetify router alignment

I'm trying to setup at route that contains just a table with a layout inspired by the Vuetify team.
I have a problem that the table does not take only a small part of the screen.
I have tried using v-layout with "row", "column" and different paddings and marging.
App.vue:
<template>
<v-app>
<router-view/>
</v-app>
</template>
<script>
export default {
name: 'App',
};
</script>
Menu.vue:
<template>
<v-container>
<v-navigation-drawer
clipped
fixed
v-model="drawer"
app
>
<v-list dense>
<v-list-tile
:to="{name: 'dashboard'}"
>
<v-list-tile-action>
<v-icon>dashboard</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Dashboard</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile
:to="{name: 'settings'}"
>
<v-list-tile-action>
<v-icon>settings</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Settings</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile
#click="logout();"
>
<v-list-tile-action>
<v-icon>logout</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Logout</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-navigation-drawer>
<v-toolbar app fixed clipped-left>
<v-toolbar-side-icon #click.stop="drawer = !drawer"></v-toolbar-side-icon>
<v-toolbar-title>Hello, {{ name }}</v-toolbar-title>
</v-toolbar>
<v-content>
<v-container fluid fill-height>
<v-layout justify-center align-center>
<v-flex shrink>
<router-view></router-view>
</v-flex>
</v-layout>
</v-container>
</v-content>
<v-footer app fixed>
<span>© arcyfelix 2019</span>
</v-footer>
</v-container>
</template>
<script>
export default {
name: 'MainMenu',
data() {
return {
drawer: false,
name: 'Wojciech',
};
},
methods: {
logout() {
this.$router.push({ name: 'home' });
},
},
};
</script>
Dashboard.vue:
<template>
<v-layout full-width>
<v-data-table
:items="desserts"
class="elevation-1"
hide-actions
hide-headers
expand
:loading="true"
>
<template v-slot:items="props">
<td class="text-xs-left">2019-07-01</td>
<td>{{ props.item.name }}</td>
<td>
<v-btn
small
depressed
flat
>
Edit
</v-btn>
</td>
</template>
</v-data-table>
</v-layout>
</template>
<script>
export default {
name: 'Dashboard',
data() {
return {
desserts: [
{
name: 'Frozen Yogurt',
},
{
name: 'Donut',
},
{
name: 'KitKat',
},
],
};
},
};
</script>
router.js:
import Vue from 'vue';
import Router from 'vue-router';
import Menu from './layouts/Menu.vue';
import MainMenu from './layouts/MainMenu.vue';
import Dashboard from './views/Dashboard.vue';
import Login from './views/Login.vue';
import Home from './views/Home.vue';
Vue.use(Router);
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: 'auth',
name: 'auth',
component: Menu,
children: [
{
path: 'dashboard',
name: 'dashboard',
component: Dashboard,
},
{
path: 'settings',
name: 'settings',
component: () => import(/* webpackChunkName: "about" */ './views/Settings.vue'),
},
],
},
{
path: '/',
name: 'mainMenu',
component: MainMenu,
children: [
{
path: 'home',
name: 'home',
component: Home,
},
{
path: 'login',
name: 'login',
component: Login,
},
{
path: 'register',
name: 'register',
component: () => import(/* webpackChunkName: "about" */ './views/Register.vue'),
},
],
},
],
});
I would like to take it 2/3 or full width of the screen.
What you really want is to put the menu outside of the router-view otherwise it has to reload on each page load. You also want to move the container definition inside of the v-content element and make sure it uses fill-height too less you end up with an odd background mesh.
<v-app>
<my-menu></my-menu>
<v-content>
<v-container fluid fill-height>
<router-view></router-view>
</v-container>
</v-content>
</v-app>
Now just change your Dashboard code and layout:
<v-layout row wrap>
<v-flex xs12>
//the rest of the dashboard code
</v-flex>
</v-layout
And you're good to go.

computed property 'name' was assigned but it has not setter (without v-model)

I'm trying to make a navigation Active when it is clicked on by adding the class nav-selected. I've seen other questions like this but they are related to v-model hence they didn't help me.
I need to make sure that it is added to the store so that I can always see what page is active even after a refresh. However I'm receiving the following error:
Navigation.vue:
<template>
<v-container>
<v-layout align-center>
<!-- Logo -->
<v-flex sm2>
<img src="http://beam.space/img/icon.png" height="30px">
</v-flex>
<!-- Navigation -->
<v-flex sm8>
<v-layout wrap justify-center>
<v-flex sm2>
<router-link to="/myspaces">
<h2 #click="setActiveNav(0)" :class="{'nav-selected': activeNavigation === 0}" class="nav-text">My Spaces</h2>
</router-link>
</v-flex>
<v-flex sm2>
<router-link to="/inspirations">
<h2 #click="setActiveNav(1)" :class="{'nav-selected': activeNavigation === 1}" class="nav-text">Inspirations</h2>
</router-link>
</v-flex>
</v-layout>
</v-flex>
<v-flex sm2>
<p>profile</p>
</v-flex>
</v-layout>
</v-container>
</template>
<script>
import { mapState } from 'vuex';
export default {
name: "navigation",
computed: {
...mapState([
'activeNavigation'
])
},
methods: {
setActiveNav(activeNav) {
this.activeNavigation = activeNav;
this.store.commit('setActiveNavigation', this.activeNavigation);
}
}
}
</script>
<style scoped>
</style>
Store.js:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
export default new Vuex.Store({
state: {
activeNavigation: 0
},
getters: {
},
mutations: {
// Set Active navigation on click.
setActiveNavigation(state, id) {
state.activeNavigation = id;
}
},
// actions zijn a sync
actions: {
}
});
mapState creates getter properties only. You cannot assign to those properties.
There is no need to assign to activeNavigation anyway, the commit will update the mapped value of activeNavigation automatically.
Change this:
setActiveNav(activeNav) {
this.activeNavigation = activeNav; // <-- Not allowed
this.store.commit('setActiveNavigation', this.activeNavigation);
}
to this:
setActiveNav(activeNav) {
this.$store.commit('setActiveNavigation', activeNav);
}