Working with Vue cli 3 and vuex for the first time and trying to get a simple login working with vuex but the getters I have setup are not getting any data from the vuex store and just return nothing even with a state change.
Here's my store.ts:
export default new Vuex.Store({
state: {
loggedIn: true,
email: 'test',
password: 'test',
},
getters: {
loggedIn(state) {
return state.loggedIn;
},
userEmail(state) {
return state.email;
},
},
mutations: {
login(state, user) {
state.loggedIn = true;
state.email = user.e;
state.password = user.p;
},
logout(state) {
state.loggedIn = false;
},
},
actions: {
login(context, data) {
context.commit('login', data);
},
logout(context) {
context.commit('logout');
},
},
});
and the navbar.vue where im trying to change the nav based on if a user is logged in.
html
<template>
<nav id="nav" class="navbar fixed-top navbar-expand-md navbar-light bg-light">
<router-link to="/" class="navbar-brand">Navbar</router-link>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#topNav" aria-controls="topNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="topNav">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<router-link to="/" class="nav-link">Home</router-link>
</li>
<li class="nav-item" v-if="loggedIn">
<router-link to="/Dashboard" class="nav-link">Dashboard</router-link>
</li>
<li class="nav-item" v-else>
<router-link to="/Login" class="nav-link">Login</router-link>
</li>
<li class="nav-item">
<p class="nav-link">user : {{ test }}</p>
</li>
</ul>
</div>
</nav>
</template>
typescript
import { Component, Vue } from 'vue-property-decorator';
import { mapState, mapGetters } from 'vuex';
#Component({
computed: mapState(['loggedIn']),
})
#Component
export default class NavBar extends Vue {
private test: string = 'test';
constructor() {
super();
}
}
Related
This is my first project in vue and it is being very difficult for me to find functional examples in vue.
I'm trying to make a header component that shows a list of links, some of which I need to be a drop-down list of links. Here is my component
<template>
<nav class='header'>
<ul class='menu'>
<li class='menu-item'>
<a class='menu-link' href="https://www.esthima.fr/societe">QUI SOMMES-NOUS ?</a>
</li>
<li class="menu-item menu-item-dropdown" v-on:click="toggle('ranking')" v-bind:class="{'open' : dropDowns.ranking.open}">
<a class='menu-link menu-link-toggle'>QUAND L’ANIMAL S’EN VA</a>
<ul class='dropdown-menu'>
<li class='dropdown-menu-item'>
<a class='dropdown-menu-link'>TEST 1</a>
</li>
<li class='dropdown-menu-item'>
<a class='dropdown-menu-link'>TEST 2</a>
</li>
</ul>
</li>
<li class='menu-item'>
<a class='menu-link' href="https://boutique.esthima.fr">URNES ANIMAUX</a>
</li>
</ul>
<img src="../assets/logoesthima.png">
<a>NOS SERVICES</a>
URNES ANIMAUX
<a>TARIFS ET DEVIS</a>
<a>NOUS CONTACTER</a>
</nav>
</template>
<script>
export default{
let header = new Vue({
al: '.header',
ready: function()
{
var self = this
window.addEventListener('click', function(e){
if (! e.target.parentNode.classList.contains('menu__link--toggle'))
{
self.close()
}
}, false)
},
data: {
dropDowns: {
ranking: { open: false}
}
},
methods: {
toggle: function(dropdownName)
{
//alert(dropdownName)
this.dropDowns[dropdownName].open = !this.dropDowns[dropdownName].open;
},
close: function()
{
for (dd in this.dropDowns)
{
this.dropDowns[dd].open = false;
}
}
}
})
}
</script>
I'm following the few examples I've found and the documentation and they all return the same console loading error with the declaration inside the "new Vue" script whether I declare it directly or keep it as a constant.
Someone who can make me see my mistake.
Thank you very much in advance!
You should change the code to be a properly structured Single-File Component:
<template>
<nav class='header'>
<ul class='menu'>
<li class='menu-item'>
<a class='menu-link' href="https://www.esthima.fr/societe">
QUI SOMMES-NOUS ?
</a>
</li>
<li class="menu-item menu-item-dropdown" #click="toggle('ranking')" :class="{open: dropDowns.ranking.open}">
<a class='menu-link menu-link-toggle'>
QUAND L’ANIMAL S’EN VA
</a>
<ul class='dropdown-menu'>
<li class='dropdown-menu-item'>
<a class='dropdown-menu-link'>TEST 1</a>
</li>
<li class='dropdown-menu-item'>
<a class='dropdown-menu-link'>TEST 2</a>
</li>
</ul>
</li>
<li class='menu-item'>
<a class='menu-link' href="https://boutique.esthima.fr">URNES ANIMAUX</a>
</li>
</ul>
<img src="../assets/logoesthima.png">
<a>NOS SERVICES</a>
URNES ANIMAUX
<a>TARIFS ET DEVIS</a>
<a>NOUS CONTACTER</a>
</nav>
</template>
<script>
export default
{
mounted()
{
window.addEventListener('click', (evt) =>
{
if (! e.target.parentNode.classList.contains('menu__link--toggle'))
{
this.close()
}
}, false)
},
data()
{
return {
dropDowns:
{
ranking:
{
open: false
}
}
};
},
methods:
{
toggle(dropdownName)
{
//alert(dropdownName)
this.dropDowns[dropdownName].open = !this.dropDowns[dropdownName].open;
},
close()
{
for (dd in this.dropDowns)
{
this.dropDowns[dd].open = false;
}
}
}
};
</script>
From the api I get a list of categories, and for some reason, the filtered subcategories (SUB_CATS) are not displayed. Maybe I don’t pass them correctly to the component?
I want to click on the link and get subcategories on a new page or when hovering get list of SUB_CATS.
export const getters = {
ALL_CATS(state){
return state.categories;
},
MAIN_CATS(state){
return state.categories.filter(c => c.parent_id === 0);
},
SUB_CATS: state => id => {
return state.categories.filter(c => c.parent_id === id);
},
};
component
import {mapActions, mapGetters} from 'vuex'
export default {
computed: {
...mapGetters([
'ALL_CATS',
'MAIN_CATS',
'SUB_CATS',
]),
},
methods: {
...mapActions([
'GET_CATEGORIES'
]),
},
mounted() {
this.GET_CATEGORIES()
},
}
<div class="menu">
<div class="menu-title">
<nuxt-link to="/allcats/">allcats</nuxt-link>
</div>
<ul class="menu-list">
<li class="menu-item"
v-for="category in MAIN_CATS"
:key="category.id">
<nuxt-link :to="`/category/${category.id}`" class="menu-button">{{ category.title }} {{ category.id}}</nuxt-link>
<ul class="menu-sub-list">
<li class="menu-item"
v-for="sub in SUB_CATS"
:key="sub.title">
<nuxt-link :to="`/category/${sub.id}`" class="menu-button">{{ sub.title }} {{sub.id}}</nuxt-link>
</li>
</ul>
</li>
</ul>
</div>
I have a list of components rendered in a a v-for. I want to set the "show" Boolean property as false in the other components when one of them is set to true:
To simplify I am only adding two components
Main component code:
<template>
<aside class="main-sidebar">
<section class="sidebar">
<ul class="sidebar-menu" data-widget="tree">
<nav-bar-user-profile-item></nav-bar-user-profile-item>
<nav-bar-item></nav-bar-item>
<nav-bar-item></nav-bar-item>
</ul>
</section>
</aside>
</template>
<script>
import NavBarUserProfileItem from '#/components/NavBar/NavBarUserProfileItem';
import NavBarItem from '#/components/NavBar/NavBarItem';
export default {
name: 'NavBar',
components: {
NavBarUserProfileItem,
NavBarItem
},
methods: {
MenuHasBeenToggled(event) {
console.log(event);
}
}
}
NavBarItemComponent
<template>
<li class="treeview2 item" :class="{'menu-open': isOpen, 'active': menu.active}" #click="ToggleState">
<a href="#">
<i class="fa fa-th"></i>
<span>{{ menu.title }}</span>
<span class="pull-right-container">
<i class="fa fa-angle-right pull-right"></i>
</span>
</a>
<collapse-transition>
<ul class="treeview-menu" v-show="isOpen">
<li v-for="submenu in menu.submenus" :key="submenu.title" :class="{'active': (('active' in submenu) ? submenu.active : false)}">
<b-link :href="submenu.link">
<i class="fa fa-circle-thin"></i>
{{ submenu.title }}
</b-link>
</li>
</ul>
</collapse-transition>
</li>
</template>
<script>
export default {
name: 'NavBarItem',
data: function () {
return {
isOpen: false
}
},
computed: {
},
methods: {
ToggleState() {
this.isOpen = !this.isOpen;
this.$emit("toggle-state");
}
},
props: {
menu: {
type: Object,
default: function() {
return {
link: "#",
title: "Main menu",
active: true,
submenus: [
{
link: "#",
title: "Submenu 1",
},
{
link: "#",
title: "Submenu 2",
active: true
},
{
link: "#",
title: "Submenu 3",
},
]
}
}
}
}
}
</script>
<style scoped>
</style>
The goal is to click on one of the and show the menu contents while at the same time collapse the other components.
I thought about using an array of variables and bind it to the "show" prop and with an event listen to it and set every variable to false except the one form the component that sent the event.
How can I know which component sent the event?
Any better idea on how to accomplish this task?
I think, the best way to do it is to add a uniuque identifier property to each NavBarItem and a property for a selected NavBarItem. Then in the main component you can on click on NavBarItem set selected NavBarItem and in NavBarItem make the isOpen computed on the basis if current NavBarItem identifier equals the clicked NavBarItem. Something like this:
<template>
<aside class="main-sidebar">
<section class="sidebar">
<ul class="sidebar-menu" data-widget="tree">
<nav-bar-user-profile-item></nav-bar-user-profile-item>
<nav-bar-item item-id="1" :selected-item-id="selectedNavbarItemId" #click="selectedNavBarItemId = 1"></nav-bar-item>
<nav-bar-item item-id="2" :selected-item-id="selectedNavbarItemId" #click="selectedNavBarItemId = 2"></nav-bar-item>
</ul>
</section>
</aside>
</template>
<script>
import NavBarUserProfileItem from '#/components/NavBar/NavBarUserProfileItem';
import NavBarItem from '#/components/NavBar/NavBarItem';
export default {
name: 'NavBar',
components: {
NavBarUserProfileItem,
NavBarItem
},
data: function(){
return {
selectedNavBarItemId: 0
}
},
methods: {
MenuHasBeenToggled(event) {
console.log(event);
}
}
}
And in NavBarItem
<template>
<li class="treeview2 item" :class="{'menu-open': isOpen, 'active': menu.active}" #click="ToggleState">
<a href="#">
<i class="fa fa-th"></i>
<span>{{ menu.title }}</span>
<span class="pull-right-container">
<i class="fa fa-angle-right pull-right"></i>
</span>
</a>
<collapse-transition>
<ul class="treeview-menu" v-show="isOpen">
<li v-for="submenu in menu.submenus" :key="submenu.title" :class="{'active': (('active' in submenu) ? submenu.active : false)}">
<b-link :href="submenu.link">
<i class="fa fa-circle-thin"></i>
{{ submenu.title }}
</b-link>
</li>
</ul>
</collapse-transition>
</li>
</template>
<script>
export default {
name: 'NavBarItem',
data: function () {
return {
}
},
computed: {
isOpen:function(){
return itemId == selectedItemId;
}
},
methods: {
},
props: {
itemId:Number,
selectedItemId:Number,
menu: {
type: Object,
default: function() {
return {
link: "#",
title: "Main menu",
active: true,
submenus: [
{
link: "#",
title: "Submenu 1",
},
{
link: "#",
title: "Submenu 2",
active: true
},
{
link: "#",
title: "Submenu 3",
},
]
}
}
}
}
}
</script>
<style scoped>
</style>
I have a simple situation that I want to render cart-badge based on window width value but it always show the last one even though windowWidth does change the value. Please advise me what to do !
<template v-if="windowWidth>=1024">
<div class="nav-user-account"> {{windowWidth}}
<div class="nav-cart nav-cart-box">
<span class="text hidden-sm">Cart</span>
<span class="cart-number" id="nav-cart-num">{{cartItemCount}}</span>
</div>
</div>
</template>
<template v-if="windowWidth<1024">
<a href="#" style="color:#ff6a00" class="icon-cart">
{{windowWidth}}
<i class="fa fa-shopping-cart fa-2x" aria-hidden="true"></i>
<span class="cart-num">2</span>
</a>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
data() {
return {
windowWidth: window.innerWidth,
}
},
computed: {
...mapGetters('cart', {
cartItemCount: 'getShoppingCartItemsCount'
})
},
mounted() {
this.$nextTick(() => {
window.addEventListener('resize', () => {
this.windowWidth= window.innerWidth
});
})
},
}
</script>
UPDATED: as Tony19 pointed out, i need a master template outside of these 2 template.
<template>
<div>
<template v-if="windowWidth>=1024">...</template>
<template v-else></template>
</div>
</template>
I have the following code and it works by refreshing the page it works fine, but not when clicking on the nav.
How can i achieve that when i click on users, the method fetchData will be executed? So i can see the console.log and the json data.
Navigation:
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<router-link v-for="item in items" v-if="item.navitems && item.navitems.navitem" :to="item.navitems.navitem.url" tag="li" active-class="active" exact><a>{{item.navitems.navitem.name}}</a></router-link>
Content.vue
<template>
<div>
<div class="container">
<h1>{{ slug }}</h1>
<ul v-if="items && items.length">
<li v-for="item of items">
<p><strong>{{item.name}}</strong></p>
<p>{{item.email}}</p>
</li>
</ul>
</div>
</div>
</template>
<script>
export default{
props: ['slug'],
data: () => ({
items: []
}),
created: function () {
this.fetchData();
},
methods: {
fetchData: function () {
var self = this;
console.log(this.slug);
$.get( 'http://jsonplaceholder.typicode.com/' + this.slug, function( data ) {
self.items = data;
console.log(data);
});
}
}
}
</script>
Changed created into mounted and add watch.
watch: {
'$route.params.slug'(newSlug, oldSlug) {
this.fetchData(newId);
}
}