get filtered items from vuex - vue.js

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>

Related

How to pass data on the root components in Vue

How can I pass the page_id to the Sidebar component method highlightNode(), because I want to highlight a newly added item. My current code is the page id is undefined.
This is my code & structure.
my root component is Sidebar.vue
<template>
<div>
<ul>
<li v-for="page in pages">
<div :class="{ 'highlight': highlightedNode == page.id }">
<router-link :to="'/view/' + page.id" #click.native="highlightNode(page.id)">
<span v-title="page.title"></span>
</router-link>
</div>
</li>
</ul>
</div>
</template>
export default {
data () {
return {
pages: [],
highlightedNode: null
}
},
mounted() {
this.getPages()
this.$root.$refs.Sidebar = this
},
methods: {
getPages() {
axios.get('/get-pages').then(response => {
this.pages = response.data
});
},
highlightNode(id) {
this.highlightedNode = id
},
}
}
my add new Page component AddNewPage.vue
<template>
<div>
<div class="main-header">
<div class="page-title">
<input type="text" v-model="page.title" class="form-control">
</div>
</div>
<div class="main-footer text-right">
<button class="btn btn-success btn-sm" #click="saveChanges()">Save and Publish</button>
</div>
</div>
</template>
export default {
data () {
return {
page: {
title: null,
},
}
},
mounted() {
//
},
methods: {
saveChanges() {
axios.post('/store-new-filter', this.page)
.then(response => {
const id = response.data.id // return page id
this.$root.$refs.Sidebar.highlightNode(id) // <-- this line, I want to pass page id to hightlight the newly added page.
})
.catch( error => {
})
},
}
}
Or any alternative way to achieve my expected output.
Thanks in advance.

VueJS renders variable twice in loop

When I press some key in editable <li> it shows this content twice. Out of this v-for loop, it shows only once. So in this array is for example ['a'] but in <li> it shows 'aa'
new Vue({
el: '#app',
data: {
component: {
items: ['']
}
},
methods: {
onKeydown(e, index) {
if(e.key === 'Enter') {
e.preventDefault()
this.component.items.push('')
}
},
onInput(e, index, item) {
this.component.items.splice(index, 1, e.target.innerHTML)
}
}
});
<div id="app">
<ul>
<li contenteditable="true"
v-for="(item, index) in component.items"
:key="index"
#keydown="onKeydown($event, index)"
#input="onInput($event, index, item)"
>{{ item }}</li>
</ul>
{{ component.items }}
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

Conditional rendering template on Vue?

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>

Vuex state & getters not retrieving store data in Vue cli 3

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();
}
}

Vuejs 2 reload content by changing slug

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);
}
}