I just want to add a search bar filter to my vue 3 project but I don't know why is not working as good as I wanted.
Here is my code:
App.vue
<template>
<div id="app">
<div class="header">
<img class="logo" alt="UOC logo" src="./assets/uoc-logo.png" />
<div class="app-name">Recipe book</div>
</div>
<search-bar #search="setSearchTerm" />
<recipe-list :recipeList="filteredData" #delete-recipe="deleteRecipe" />
<recipe-form
v-if="showModal"
#add-recipe="addRecipe"
#close-modal="showModal = false"
/>
</div>
</template>
<script>
import RecipeList from "./components/RecipeList.vue";
import RecipeForm from "./components/RecipeForm.vue";
import SearchBar from "./components/SearchBar.vue";
import { defineComponent } from "vue";
export default defineComponent({
name: "App",
components: {
RecipeList: RecipeList,
RecipeForm,
SearchBar,
},
data: () => ({
recipeList: [
{
id: 1,
servings: 4,
time: "30m",
difficulty: "Easy",
title: "Spaghetti",
ingredients: ["noodles", "tomato sauce", "cheese"],
directions: ["boil noodles", "cook noodles", "eat noodles"],
imageUrl:
"https://imagesvc.meredithcorp.io/v3/mm/image?q=60&c=sc&poi=face&w=2000&h=1000&url=https%3A%2F%2Fstatic.onecms.io%2Fwp-content%2Fuploads%2Fsites%2F21%2F2018%2F02%2F14%2Frecetas-4115-spaghetti-boloesa-facil-2000.jpg",
},
{
id: 2,
servings: 2,
time: "15m",
difficulty: "Medium",
title: "Pizza",
ingredients: ["dough", "tomato sauce", "cheese"],
directions: ["boil dough", "cook dough", "eat pizza"],
imageUrl:
"https://www.saborusa.com/wp-content/uploads/2019/10/Animate-a-disfrutar-una-deliciosa-pizza-de-salchicha-Foto-destacada.png",
featured: true,
},
{
id: 3,
servings: 6,
time: "1h",
difficulty: "Hard",
title: "Salad",
ingredients: ["lettuce", "tomato", "cheese"],
directions: ["cut lettuce", "cut tomato", "cut cheese"],
imageUrl:
"https://www.unileverfoodsolutions.es/dam/global-ufs/mcos/SPAIN/calcmenu/recipes/ES-recipes/In-Development/american-bbq-beef-salad/main-header.jpg",
},
],
showModal: false,
recipesData: RecipeList,
filteredData: RecipeList,
}),
methods: {
deleteRecipe(id) {
this.recipeList.splice(id, 1);
},
addRecipe(recipe) {
this.recipeList.push(recipe);
},
toggleForm() {
if (this.showModal === false) {
this.showModal = true;
}
},
setSearchTerm(value) {
console.log(value);
if (value && value.length > 0) {
this.filteredData = this.recipesData.filter((i) => {
const val = value.toLowerCase();
const title = i.title && i.title.toLowerCase();
if (val && title.indexOf(val) !== -1) {
return true;
}
return false;
});
} else {
this.filteredData = this.recipesData;
}
},
},
});
</script>
SearchBar.vue
<template>
<div class="search">
<input
type="text"
placeholder="Search for a recipe"
id="search"
#change="search"
v-model="searchText"
/>
<button #click="clearSearch">Clear search</button>
<button #click="showForm">Add a new recipe</button>
</div>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
name: "SearchBar",
data() {
return { searchText: "" };
},
methods: {
showForm() {
console.log("show");
this.$emit("show-form");
},
clearSearch() {
this.clearInput = "";
},
search() {
this.$emit("search", this.searchText);
},
},
});
</script>
The component of search bar is working but when I acces to my website the array object is broken and I can not see any recipe. I just see recipes If I find it.
Thanks for your help
Related
I have some data that I get from axios and pass to a Bootstrap table. In my computed properties where I declare the nameOfPerson field, I have made a click event, so that when a user clicks on the name, a modal opens. This modal also contains the data shown in the table.
However, I would like to change it so that when you click on the name of a person, ONLY the data for THAT single person gets passed to the modal. So instead of passing a prop containing data of ALL users the modal, I just want the data related to the name that I actually click on.
How would I accomplish this?
The parent:
<template>
<b-container>
<b-card class="mt-4">
<b-table
:items="dataItems"
:fields="fields"
:per-page="[5, 10]"
sort-desc
primary-key="id"
/>
</b-card>
<data-modal ref="dataModal" :selected-name="dataItems"/>
</b-container>
</template>
<script>
import {axiosComponent} from '#/axios/services';
import DataModal from '#/components/DataModal';
export default {
components: {
DataModal
},
data() {
return {
dataItems: null,
};
},
computed: {
fields() {
return [
{
key: 'nameOfperson',
label: 'name',
sortable: true
click: () => this.$refs.dataModal.show(),
},
{
key: 'ageOfPerson',
label: 'Age',
sortable: true
},
]
},
},
methods: {
load(){
axiosComponent.getData().then(result => {
this.dataItems = result.data
})
}
},
created() {
this.load()
}
};
</script>
The child (modal)
<template>
<b-modal v-model="showModal">
<div v-for="log in selectedName">
{{ log }}
</div>
</b-modal>
</template>
<script>
export default {
props: {
selectedName: Array
},
data() {
return {
showModal: false,
};
},
methods: {
show(){
this.showModal = true
}
}
};
</script>
You can use #row-selected method, take a look at following demo:
Vue.component('child', {
template: `
<b-modal v-model="showModal">
<div v-for="log in selectedName">
{{ log }}
</div>
</b-modal>
`,
props: {
selectedName: Array,
},
data() {
return {
showModal: false,
};
},
methods: {
show(){
this.showModal = true
}
}
})
new Vue({
el: "#demo",
data() {
return {
dataItems: null,
selected: null,
};
},
computed: {
fields() {
return [
{
key: 'nameOfperson',
label: 'name',
sortable: true,
},
{
key: 'ageOfPerson',
label: 'Age',
sortable: true
},
]
},
},
methods: {
load(){
// axiosComponent.getData().then(result => {
this.dataItems = [{id: 1, nameOfperson: 'aaa', ageOfPerson: 5}, {id: 2, nameOfperson: 'bbb', ageOfPerson: 25}, {id: 3, nameOfperson: 'ccc', ageOfPerson: 35}, {id: 4, nameOfperson: 'ddd', ageOfPerson: 45}]
// })
},
onRowSelected(items) {
this.selected = items
this.$refs.dataModal.show()
},
},
created() {
this.load()
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.css" />
<script src="https://unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue-icons.min.js"></script>
<div id="demo">
<b-container>
<b-card class="mt-4">
<b-table
:items="dataItems"
:fields="fields"
:per-page="5"
sort-desc
primary-key="id"
selectable
:select-mode="'single'"
#row-selected="onRowSelected"
/>
</b-card>
<child ref="dataModal" :selected-name="selected"></child>
</b-container>
</div>
I created a select2 wrapper in vue3 with options API everything working fine but the problem is that when getting values from calling API it's not selected the default value in the select2 option. but when I created a static array of objects it does. I don't know why it's working when it comes from the API
Parent Component
Here you can I passed the static options array in options props and my selected value is 2 and it's selected in my Select2 component, but when passed formattedCompanies it's not which is the same format as the static options array then why is not selected any reason here..?
<template>
<Form #submitted="store()" :processing="submitting">
<div class="row">
<div class="col-lg-6">
<div class="form-group">
<label>Company Name</label>
<Select2
:options="options"
v-model="selected"
placeholder="Select Company"
/>
<ValidationError :errors="errors" error-key="name" />
</div>
</div>
</div>
</Form>
</template>
<script>
import Form from "#/components/Common/Form";
import Select2 from "#/components/Common/Select2";
export default {
components: {
Select2,
Form
},
data() {
return {
selected : 2,
companies : [],
options: [ // static array
{ id: 1, text: 'hello' },
{ id: 2, text: 'hello2' },
{ id: 3, text: 'hello3' },
{ id: 4, text: 'hello4' },
{ id: 5, text: 'hello5' },
],
}
},
mounted() {
this.getAllMedicineCompanies()
},
computed:{
formattedCompanies() {
let arr = [];
this.companies.forEach(item => {
arr.push({id: item.id, text: item.name})
});
return arr;
}
},
methods: {
getAllMedicineCompanies(){
axios.get('/api/get-data?provider=companies')
.then(({ data }) => {
this.companies = data
})
},
}
}
</script>
Select2 Component
Here is what my select2 component look like, did I do anything wrong here, please anybody help me
<template>
<select class="form-control">
<slot/>
</select>
</template>
<script>
export default {
name: "Select2",
props: {
options: {
type: [Array, Object],
required: true
},
modelValue: [String, Number],
placeholder: {
type: String,
default: "Search"
},
allowClear: {
type: Boolean,
default: true
},
},
mounted() {
const vm = this;
$(this.$el)
.select2({ // init select2
data: this.options,
placeholder: this.placeholder,
allowClear: this.allowClear
})
.val(this.modelValue)
.trigger("change")
.on("change", function () { // emit event on change.
vm.$emit("update:modelValue", this.value);
});
},
watch: {
modelValue(value) { // update value
$(this.$el)
.val(value)
.trigger("change");
},
options(options) { // update options
$(this.$el)
.empty()
.select2({data: options});
},
},
destroyed() {
$(this.$el)
.off()
.select2("destroy");
}
}
</script>
Probably when this Select2 mounted there is no companies. It is empty array after that it will make API call and it it populates options field and clear all options.
Make:
companies : null,
Change it to
<Select2
v-if="formattedCompanies"
:options="formattedCompanies"
v-model="selected"
placeholder="Select Company"
/>
It should be like this:
<template>
<Form #submitted="store()" :processing="submitting">
<div class="row">
<div class="col-lg-6">
<div class="form-group">
<label>Company Name</label>
<Select2
v-if="formattedCompanies"
:options="formattedCompanies"
v-model="selected"
placeholder="Select Company"
/>
<ValidationError :errors="errors" error-key="name" />
</div>
</div>
</div>
</Form>
</template>
<script>
import Form from "#/components/Common/Form";
import Select2 from "#/components/Common/Select2";
export default {
components: {
Select2,
Form
},
data() {
return {
selected : 2,
companies : null,
options: [ // static array
{ id: 1, text: 'hello' },
{ id: 2, text: 'hello2' },
{ id: 3, text: 'hello3' },
{ id: 4, text: 'hello4' },
{ id: 5, text: 'hello5' },
],
}
},
mounted() {
this.getAllMedicineCompanies()
},
computed:{
formattedCompanies() {
let arr = [];
this.companies.forEach(item => {
arr.push({id: item.id, text: item.name})
});
return arr;
}
},
methods: {
getAllMedicineCompanies(){
axios.get('/api/get-data?provider=companies')
.then(({ data }) => {
this.companies = data
})
},
}
}
</script>
The problem was that my parent component and Select2 component mounted at the same time that's why my computed value is not initialized so the selected value is not selected in the option,
problem solved by setTimeOut function in mounted like this
Select2 Component
<script>
mounted() {
const vm = this;
setTimeout(() => {
$(this.$el)
.select2({ // init select2
data: this.options,
placeholder: this.placeholder,
allowClear: this.allowClear
})
.val(this.modelValue)
.trigger("change")
.on("change", function () { // emit event on change.
vm.$emit("update:modelValue", this.value);
});
}, 500)
},
</script>
I'm new in Vuejs and I'm currently working with composition API, I have a nav component where I have an Array called tabs as you can see that array is static.
So I want to do this dynamic and send that props from another component. I read about that but I do not understand at all.
Supossely I can change the array of my component with a model like:
const tabs<MyModel>
And then I can send it from the other component, but I'm lost
Nav component
<template>
<div>
<div class="sm:hidden">
<label for="tabs" class="sr-only">Select a tab</label>
<select
id="tabs"
name="tabs"
class="block w-full focus:ring-indigo-500 focus:border-indigo-500 border-gray-300 rounded-md"
>
<option v-for="tab in tabs" :key="tab.name" :selected="tab.current">
{{ tab.name }}
</option>
</select>
</div>
<div class="hidden sm:block">
<nav class="flex items-center space-x-4">
<a
v-for="tab in tabs"
:key="tab.name"
:href="tab.href"
:class="[
tab.current
? 'bg-purple-70 q0 text-white'
: 'text-purple-700 hover:text-gray-700',
'px-12 py-2 rounded-full font-bold text-xl',
]"
#click="changeTab(tab)"
>
{{ tab.name }}
</a>
</nav>
</div>
<div class="hidden sm:block">
<div
v-for="tab in tabs"
:key="tab.name"
:href="tab.href"
class="px-12 flex justify-center"
:class="[tab.current || 'hidden']"
#click="changeTab(tab)"
>
{{ tab.id }} - {{ tab.name }} - {{ tab.href }} - {{ tab.title }}
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, computed } from '#vue/composition-api'
import i18n from '#/setup/i18n'
export default defineComponent({
name: 'ProgramModal',
setup() {
const ariaLabel = computed(() => i18n.t('share') as string)
const tabs = ref([
{
id: 1,
title: 'test title one',
imageSrc: '/programs/test1.png',
content: '',
name: 'LOREM',
href: '#test1',
current: true,
},
{
id: 2,
title: 'test title two',
imageSrc: '/programs/test2.png',
content: '',
name: 'IPSUM',
href: '#test2',
current: false,
},
{
id: 3,
title: 'test title three',
imageSrc: '/programs/test3.png',
content: '',
name: 'PDF',
href: '#test3',
current: false,
},
])
const changeTab = (selectedTab: { id: number }) => {
tabs.value.map((t) => {
t.id === selectedTab.id ? (t.current = true) : (t.current = false)
})
}
return {
tabs,
changeTab,
ariaLabel,
}
},
})
</script>
The component where I want to send parameters:
<template>
<ProgramModal />
</template>
<script lang="ts">
import ProgramModal from '#/components/ProgramModal.vue'
import { defineComponent, ref } from '#vue/composition-api'
export default defineComponent({
name: 'Home',
components: {
ProgramModal,
},
setup() {
const isModalOpen = ref(true)
const showModal = () => {
isModalOpen.value = true
}
return {
isModalOpen,
showModal,
}
},
})
</script>
How can I change this logic to receive different values? Regards
Two schemes, props or composables:
1. Use props:
You can create tabs in Home component and pass to ProgramModel:
<template>
<ProgramModal :tabs="tabs" />
</template>
<script lang="ts">
import ProgramModal from '#/components/ProgramModal.vue'
import { defineComponent, ref } from '#vue/composition-api'
export default defineComponent({
name: 'Home',
components: {
ProgramModal,
},
setup() {
// ...
const tabs = ref([
{
id: 1,
title: 'test title one',
imageSrc: '/programs/test1.png',
content: '',
name: 'LOREM',
href: '#test1',
current: true,
},
{
id: 2,
title: 'test title two',
imageSrc: '/programs/test2.png',
content: '',
name: 'IPSUM',
href: '#test2',
current: false,
},
{
id: 3,
title: 'test title three',
imageSrc: '/programs/test3.png',
content: '',
name: 'PDF',
href: '#test3',
current: false,
},
])
return { tabs }
},
})
</script>
Then, define a prop in ProgramModal component:
export default defineComponent({
name: 'ProgramModal',
props: {
tabs: Array as PropType<Array<Tab>>
},
setup() {
const ariaLabel = computed(() => i18n.t('share') as string)
const changeTab = (selectedTab: { id: number }) => {
tabs.value.map((t) => {
t.id === selectedTab.id ? (t.current = true) : (t.current = false)
})
}
return {
tabs,
changeTab,
ariaLabel,
}
},
})
2. Use composables (Vue3 recommend)
You can define a file named useTab:
// useTab.js
const tabs = ref([
{
id: 1,
title: 'test title one',
imageSrc: '/programs/test1.png',
content: '',
name: 'LOREM',
href: '#test1',
current: true,
},
{
id: 2,
title: 'test title two',
imageSrc: '/programs/test2.png',
content: '',
name: 'IPSUM',
href: '#test2',
current: false,
},
{
id: 3,
title: 'test title three',
imageSrc: '/programs/test3.png',
content: '',
name: 'PDF',
href: '#test3',
current: false,
},
]);
export default function (
const changeTab = (selectedTab: { id: number }) => {
tabs.value.map((t) => {
t.id === selectedTab.id ? (t.current = true) : (t.current = false)
})
}
return { tabs, changeTab }
)
Then, you can use it anywhere.
// Home.vue
export default defineComponent({
name: 'Home',
components: {
ProgramModal,
},
setup() {
// ...
// By this way, you can change tab in Home or anywhere you want.
const { changeTab } = useTab();
return { }
},
})
// ProgramModal.vue
export default defineComponent({
name: 'ProgramModal',
setup() {
const ariaLabel = computed(() => i18n.t('share') as string)
const { tabs, changeTab } = useTab();
return {
tabs,
changeTab,
ariaLabel,
}
},
})
By the way, method 2 is the real composition api. :)
I have a series of products, and I'm trying to set my app up in a way that let's me send someone a link directly to a product.
Everything works fine when you try to navigate to a product directly, but if you open that same url directly (without navigating there through the app), it doesn't work.
The issue is coming from subcategoryItems being undefined in the single item view
Router snippet:
{
path: '/categories',
name: 'categories',
components: { default: Categories, header: StarterNavbar, footer: StarterFooter },
props: {
header: { colorOnScroll: 400 },
footer: { backgroundColor: 'black' }
}
},
{
path: '/categories/:catname',
name: 'products',
components: { default: Products, header: StarterNavbar, footer: StarterFooter },
props: {
header: { colorOnScroll: 400 },
footer: { backgroundColor: 'black' }
}
},
{
path: '/categories/:catname/:productname',
name: 'singleproduct',
components: { default: SingleProduct, header: StarterNavbar, footer: StarterFooter },
props: {
header: { colorOnScroll: 400 },
footer: { backgroundColor: 'black' }
}
},
Product View
<template>
<div class="">
<section class="subcategory-container" v-for="(category, index) in subcats" v-bind:key="index">
<h2>{{category.subcategoryTitle}}</h2>
<card class="card-shell" v-for="(product, index) in category.subcategoryItems" v-bind:key="index">
<div class="image-container">
<img slot="image" class="card-img-top" :src="product.image" alt="Card image cap">
</div>
<div>
<h4 class="card-title">{{product.title}}</h4>
<p class="card-text">{{product.sku}}</p>
<div>
<router-link :to="{ name: 'singleproduct', params: { productname: product.title, subcatTitle: category.subcategoryTitle } }" class="text-white">
<n-button type="primary">{{buttonText}}</n-button>
</router-link>
</div>
</div>
</card>
</section>
</div>
</template>
<script>
import { Card, Button, Modal } from '#/components';
import axios from 'axios'
export default {
name: 'products',
components: {
Card,
Modal,
[Button.name]: Button
},
async created() {
const url = this.$route.params.catname;
try {
const res = await axios.get(`/products/${url}.json`);
this.subcats = res.data;
this.catname = url;
} catch (e) {
console.log(e);
}
},
data() {
return {
subcats: [],
modals: {
classic: false
},
showModal(product) {
this.modals.classic = true;
this.selectedItem = product;
},
buttonText: "Product Info",
selectedItem: '',
catname: ''
}
}
};
single item view:
<template>
<card class="card-nav-tabs text-center" header-classes="card-header-warning">
<div slot="header" class="mt-2">
<img src="" alt="">
</div>
<h4 class="card-title">{{product.title}}</h4>
<p class="card-text">{{product.description}}</p>
<div slot="footer" class="card-footer text-muted mb-2">
{{product.sku}}
</div>
</card>
</template>
<script>
import { Card, Button } from '#/components';
import axios from 'axios';
import { async } from 'q';
export default {
name: 'singleproduct',
components: {
Card,
[Button.name]: Button
},
async created() {
const { catname, productname, subcatTitle } = this.$route.params;
//console.log(this.$route.params)
try {
const res = await axios.get(`/products/${catname}.json`);
const data = res.data;
const items = data.find(product => product.subcategoryTitle === subcatTitle).subcategoryItems;
const item = items.find(item => item.title === productname);
console.log(item);
this.product = item;
} catch (e) {
console.log(e);
}
},
data () {
return {
product: []
}
}
}
</script>
Json sample:
[
{
"subcategoryTitle": "sub cat title 1",
"subcategoryItems": [
{
"id": 1,
"title": "name 1",
"sku": "sku 1",
"image": "img/path to image",
"description": "Cream beans medium rich breve cinnamon latte. White pumpkin spice kopi-luwak sugar foam frappuccino dark. Brewed arabica, dripper arabica as milk turkish medium."
}
]
},
{
"subcategoryTitle": "sub cat title 2",
"subcategoryItems": [
{
"id": 1,
"title": "name 2",
"sku": "sku 2",
"image": "img/path to image"
"description": "Cream beans medium rich breve cinnamon latte. White pumpkin spice kopi-luwak sugar foam frappuccino dark. Brewed arabica, dripper arabica as milk turkish medium."
},
{
"id": 2,
"title": "name 2",
"sku": "sku 2",
"image": "img/path to image",
"description": "Cream beans medium rich breve cinnamon latte. White pumpkin spice kopi-luwak sugar foam frappuccino dark. Brewed arabica, dripper arabica as milk turkish medium."
}
]
}
]
Thank you
This requires history mode enabled in the router. The router documentation has an explanation and example for this:
https://router.vuejs.org/guide/essentials/history-mode.html
If you look at the code I posted, the issue was that I was missing a slug in the URL for the final product page.
When I navigated there through the app, the product info was all there, but on reload, it didn't match the route anymore, so the details vanished.
I have a component with a v-for div. each item has a click function access their respective children object. I need to have a back button that would refresh the v-for div but using the ParentId of the current item I'm in.
Scan view:
<template>
<div p-0 m-0>
<div v-show="!currentItem" class="scanBreadcrumbs">
<h2>Show location</h2>
</div>
<div v-for="item in items" :key="item.id" :item="item">
<SubScan
v-show="currentItem && currentItem.id === item.id"
:item="item"
></SubScan>
<p
class="locationBox"
#click="swapComponent(item)"
v-show="path.length === 0"
>
{{ item.title }}
</p>
</div>
</div>
</template>
<script>
import { mapGetters } from "vuex";
import { SubScan } from "#/components/scan";
export default {
name: "Scan",
components: {
SubScan
},
computed: {
...mapGetters(["getResourceHierarchy", "getIsDarkMode", "getFontSize"])
},
methods: {
swapComponent(item) {
this.path.push(item.title);
this.currentItem = item;
}
},
data: () => ({
currentItem: null,
path: [],
items: [
{
parentId: null,
id: 11,
title: "Location 1",
items: [
{
parentId: 11,
id: 4324,
title: "Row 1",
items: [
{
parentId: 4324,
id: 4355,
title: "Row 1.1",
items: [
{
parentId: 4355,
id: 64645,
title: "Row 1.2",
items: [
{
parentId: 64645,
id: 7576657,
title: "Row 1.3",
items: [
{
parentId: 7576657
id: 8686,
title: "Row 1.4",
items: [
{
parentId: 8686,
id: 234324,
title: "QR Code"
}
]
}
]
}
]
}
]
}
]
}
]
}
]
})
};
</script>
SubScan component where the back button is:
<template>
<div>
<div class="scanBreadcrumbs">
<h2 v-show="path">{{ path.join(" / ") }}</h2>
</div>
<div>
<div class="showList" v-for="item in itemChildren" :key="item.id">
<p class="locationBox" #click="swapComponent(item)">
{{ item.title }}
</p>
<div class="backButton">
<v-icon #click="swapPrevious(item)" class="arrow"
>fa-arrow-left</v-icon
>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "SubScan",
props: {
item: {
type: Object,
required: true
}
},
data: () => ({
currentItem: null,
secondaryPath: [],
parentPath: []
}),
methods: {
swapComponent(item) {
console.log(item.parentId);
this.path.push(item.title);
this.parentPath.push(this.currentItem);
this.currentItem = item;
},
swapPrevious(item) {
console.log(item);
this.path.pop(this.currentItem.title);
this.currentItem = item.id;
}
},
computed: {
items(currentItem) {
return this.currentItem ? this.item.items : this.item.items;
},
itemChildren(currentItem) {
return this.currentItem ? this.currentItem.items : this.item.items;
},
path() {
return this.secondaryPath.concat(this.item.title);
}
}
};
</script>
I can only go back to the children of the object I clicked on in Scan view.
Thank you for your time.
I managed to fix my problem by assigning parent objects to each children. Then I
moved everything to Scan.vue for simplicity. This is my first project using Vue
so things might not be optimal. Scan.vue
<template>
<div p-0 m-0>
<div class="scanBreadcrumbs">
<h2 v-show="path">{{ path.join("/") }}</h2>
<h2 v-if="path.length === 0">Show location</h2>
</div>
<div>
<div v-for="item in items">
<p class="locationBox" #click="swapComponent(item)">
{{ item.title }}
</p>
</div>
<div v-if="path.length > 0">
<div class="backButton">
<v-icon #click="swapPrevious()" class="arrow">fa-arrow-left</v-icon>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from "vuex";
export default {
name: "Scan",
computed: {
...mapGetters(["getResourceHierarchy", "getIsDarkMode", "getFontSize"])
},
methods: {
swapComponent(item) {
this.path.push(item.title);
this.currentItem = item;
this.items = this.currentItem.items;
},
assignParent(children, parent) {
children.forEach(item => {
item.Parent = parent;
var parentTitle = "";
if (parent) parentTitle = parent.title;
if (item.items) {
this.assignParent(item.items, item);
}
});
},
swapPrevious() {
if (this.currentItem.parentId === null) {
this.items = this.initialItems;
this.path.pop(this.currentItem.title);
} else {
this.currentItem = this.currentItem.Parent;
this.items = this.currentItem.items;
this.path.pop(this.currentItem.title);
}
}
},
mounted: function() {
this.assignParent(this.items, null);
this.initialItems = this.items;
},
data: () => ({
currentItem: null,
path: [],
initialItems: [],
items: [
{
parentId: null,
id: 11,
title: "Location 1",
items: [
{
parentId: 11,
id: 4324,
title: "Row 1",
items: [
{
parentId: 4324,
id: 4355,
title: "Row 1.1",
items: [
{
parentId: 4355,
id: 64646,
title: "Row 1.2",
items: [
{
parentId: 64646,
id: 7576657,
title: "Row 1.3",
items: [
{
parentId: 7576657,
id: 8686,
title: "Row 1.4",
items: [
{
parentId: 8686,
id: 12313,
title: "Row 1.5",
items: [
{
parentId: 12313,
id: 234324,
title: "QR Code"
}
]
}
]
}
]
}
]
}
]
}
]
}
]
}
]
})
};
</script>
<style lang="scss" scoped></style>