I’m working on an issue tracking system using vue. I have a side bar where the user can choose a project and can view the project’s issues in a table. Everything works fine. However, the weird thing is that if the user has one issue only, it shows in the wrong project’s table. If another issue is added, that issues then goes back to the correct table.
The way the code works, is that VerticalNavMenu gets all the projects, using axios, and creates a 2d list were each sub array contains the issues of a certain project and have the same index(i.e if project x has an index 3 in the porjects array, its issues are at index 3 in the 2d list)
VerticalNavMenu.vue
<template>
<v-navigation-drawer
:value="isDrawerOpen"
app
expand-on-hover
mini-variant-width="60px"
floating
width="260"
class="app-navigation-menu"
:right="$vuetify.rtl"
@input="val => $emit('update:is-drawer-open', val)"
>
<!-- Navigation Header -->
<div class="vertical-nav-header d-flex items-center ps-6 pe-5 pt-5 pb-2">
<router-link to="/" class="d-flex align-center text-decoration-none">
<v-slide-x-transition>
<h2 class="app-title text--primary">ITrackerHub</h2>
</v-slide-x-transition>
</router-link>
</div>
<!-- Navigation Items -->
<v-list expand shaped class="vertical-nav-menu-items pr-5">
<nav-menu-link
title="Dashboard"
:to="{ name: 'dashboard' }"
:icon="icons.mdiHomeOutline"
></nav-menu-link>
<v-list>
<v-list-group :prepend-icon="icons.mdiTelevisionGuide">
<template v-slot:activator>
<v-list-item-content>
<v-list-item-title v-text="'My Projects'"></v-list-item-title>
</v-list-item-content>
</template>
<v-list-item v-for="(project, index) in ProjectList" :key="index">
<v-icon class="mx-2">{{ icons.mdiAccountGroup }}</v-icon>
<v-list-item-content>
<router-link
class="d-flex align-center text-decoration-none black--text"
:to="{ name: 'ProjectPage', params: { id: project.id, project, ProjectIssuesList, index } }"
>
{{ project.title }}
</router-link>
</v-list-item-content>
</v-list-item>
</v-list-group>
</v-list>
<nav-menu-link title="My Issues" :to="{ name: 'MyIssues' }" :icon="icons.mdiBookEditOutline"></nav-menu-link>
<nav-menu-link
style="position:relative; top:70px;"
title="Account Settings"
:to="{ name: 'pages-account-settings' }"
:icon="icons.mdiAccountCogOutline"
></nav-menu-link>
<nav-menu-link
style="position: relative; top: 200px"
title="Create Project"
:to="{ name: 'CreateProject' }"
:icon="icons.mdiPlusMinus"
></nav-menu-link>
</v-list>
</v-navigation-drawer>
</template>
<script>
// eslint-disable-next-line object-curly-newline
import {
mdiHomeOutline,
mdiAlphaTBoxOutline,
mdiEyeOutline,
mdiCreditCardOutline,
mdiTable,
mdiFileOutline,
mdiFormSelect,
mdiAccountCogOutline,
mdiAccountGroup,
mdiAccountMultiple,
mdiTelevisionGuide,
mdiBookEditOutline,
mdiPlusMinus,
} from '@mdi/js'
// import NavMenuSectionTitle from './components/NavMenuSectionTitle.vue'
import NavMenuGroup from './components/NavMenuGroup.vue'
import NavMenuLink from './components/NavMenuLink.vue'
import { mapGetters, mapActions } from 'vuex'
export default {
components: {
// NavMenuSectionTitle,
NavMenuGroup,
NavMenuLink,
},
computed: {
...mapGetters(['ProjectList']),
...mapGetters(['ProjectIssuesList']),
},
methods: {
...mapActions(['getProjectList'])
},
created() {
this.getProjectList()
},
props: {
isDrawerOpen: {
type: Boolean,
default: null,
},
},
setup() {
return {
icons: {
mdiHomeOutline,
mdiAlphaTBoxOutline,
mdiEyeOutline,
mdiCreditCardOutline,
mdiTable,
mdiFileOutline,
mdiFormSelect,
mdiAccountCogOutline,
mdiAccountGroup,
mdiAccountMultiple,
mdiTelevisionGuide,
mdiBookEditOutline,
mdiPlusMinus,
},
}
},
}
</script>
<style lang="scss" scoped>
.app-title {
font-size: 1.25rem;
font-weight: 700;
font-stretch: normal;
font-style: normal;
line-height: normal;
letter-spacing: 0.3px;
}
// ? Adjust this `translateX` value to keep logo in center when vertical nav menu is collapsed (Value depends on your logo)
.app-logo {
transition: all 0.18s ease-in-out;
.v-navigation-drawer--mini-variant & {
transform: translateX(-10px);
}
}
@include theme(app-navigation-menu) using ($material) {
background-color: map-deep-get($material, 'background');
}
.app-navigation-menu {
.v-list-item {
&.vertical-nav-menu-link {
::v-deep .v-list-item__icon {
.v-icon {
transition: none !important;
}
}
}
}
}
</style>
NavBar.js (for vuex)
import axios from 'axios'
const state = {
Projects: [],
ProjectsIssuesList: []
}
const getters = {
ProjectList: (state) => state.Projects,
ProjectIssuesList: (state) => state.ProjectsIssuesList
}
const actions = {
async getProjectList({ commit }) {
var projectList = []
var issuesList = []
await axios
.get('https://fadiserver.herokuapp.com/api/v1/my-projects/')
.then(response => {
projectList = response.data
for (let i = 0; i < projectList.length; i++) {
let projectid = projectList[i].id
axios
.get('https://fadiserver.herokuapp.com/api/v1/my-issues-titles/?projectid=' + projectid)
.then(response => {
issuesList.push(response.data)
})
.catch(error => {
console.log(error)
})
}
})
.catch(error => {
console.log(error)
})
commit('setProjects', projectList),
commit('setProjectsIssues', issuesList)
},
}
const mutations = {
setProjects: (state, Projects) => (state.Projects = Projects),
setProjectsIssues: (state, ProjectsIssuesList) => (state.ProjectsIssuesList = ProjectsIssuesList)
}
export default {
state,
getters,
actions,
mutations
}
ProjectPage.vue
<template>
<v-card>
<v-card-title class="text-center justify-center py-6">
<h1 class="font-weight-bold text-h2 basil--text">
{{ project.title }}
</h1>
</v-card-title>
<v-tabs v-model="tab" background-color="primary" dark centered>
<v-tab v-for="item in items" :key="item.tab">{{ item.tab }}</v-tab>
</v-tabs>
<v-tabs-items v-model="tab">
<v-tab-item v-for="item in items" :key="item.tab">
<v-card flat>
<v-card v-if="item.tab == 'Issues'">
<template>
<AddIssue :projectid="id"></AddIssue>
<!-- <div class="text-center">
<v-dialog v-model="dialog" width="500">
<template v-slot:activator="{ on }">
<v-btn class="success" dark v-on="on">
<v-icon align-self: left>
mdi-plus-thick
</v-icon>
Add Issue
</v-btn>
</template>
<v-card>
<v-card-title>
<h2>Add Issue</h2>
</v-card-title>
<v-card-text>
<v-form class="px-3">
<v-text-field v-model="title" label="Title"></v-text-field>
<v-textarea v-model="description" label="Description"></v-textarea>
<v-select
item-text="text"
item-value="value"
:items="time_est"
v-model="time_estimate"
label="Time Estimate"
></v-select>
<v-select
item-text="title"
item-value="id"
:items="issueType"
v-model="issue_type"
label="Issue Type"
></v-select>
<v-select
item-text="title"
item-value="id"
v-model="issue_status"
label="Issue Status"
:items="issueStatus"
></v-select>
<v-select
item-text="title"
item-value="id"
:items="issueSeverity"
v-model="issue_severity"
label="Issue Severity"
></v-select>
<v-spacer></v-spacer>
<v-btn
flat
@click="
postIssue()
reloadPage()
"
class="success mx-0 mt-3"
>
<v-icon align-self:left>mdi-content-save-check-outline</v-icon> Save</v-btn
>
</v-form>
</v-card-text>
</v-card>
</v-dialog>
</div> -->
</template>
<v-card>
<v-data-table
:headers="headers"
:items="ProjectIssuesList[index]"
item-key="full_name"
class="table-rounded"
hide-default-footer
enable-sort
@click:row="handleClick"
>
</v-data-table>
</v-card>
</v-card>
</v-card>
</v-tab-item>
</v-tabs-items>
</v-card>
</template>
<script>
import axios from 'axios'
import AddIssue from './AddIssue.vue'
export default {
props: ['id', 'project', 'ProjectIssuesList', 'index'],
components: {
AddIssue
},
data() {
return {
tab: null,
items: [{ tab: 'Issues' }, { tab: 'Calender' }, { tab: 'About' }],
title: '',
description: '',
time_estimate: '',
issue_type: '',
issue_status: '',
issue_severity: '',
time_est: [
{ value: '1', text: '1' },
{ value: '2', text: '2' },
{ value: '3', text: '3' },
{ value: '4', text: '4' },
{ value: '5', text: '5' },
{ value: '6', text: '6' },
{ value: '7', text: '7' },
{ value: '8', text: '8' },
],
}
},
setup() {
return {
headers: [
{ text: 'Title', value: 'title' },
{ text: 'Description', value: 'description' },
{ text: 'Estimate', value: 'time_estimate' },
{ text: 'Assignees', value: 'user' },
{ text: 'Type', value: 'issueType' },
{ text: 'Status', value: 'issueStatus' },
{ text: 'Severity', value: 'issueSeverity' },
],
}
},
methods: {
handleClick(issue) {
this.$router.push({
name: 'IssuePage',
params: { id: issue.id, issue },
})
},
postIssue() {
axios
.post('https://fadiserver.herokuapp.com/api/v1/my-issues/', {
title: this.title,
description: this.description,
time_estimate: this.time_estimate,
userid: 'f3260d22-8b5b-4c40-be1e-d93ba732c576',
projectid: this.id,
issueTypeId: this.issue_type,
issueStatusId: this.issue_status,
issueSeverityId: this.issue_severity,
})
.then(response => {
console.log(response)
})
},
reloadPage() {
window.location.reload()
},
},
}
</script>
<style scoped>
.v-btn {
left: 43%;
}
</style>