Vuetify breadcrumbs scoped slot - vue.js

I'm trying to incorporate breadcrumbs into my vuetify app however this is my code:
<v-breadcrumbs divider=">">
<v-breadcrumbs-item
v-for="breadcrumb in breadcrumbs"
exact
:to="breadcrumb.to">
{{ breadcrumb.text }}
</v-breadcrumbs-item>
</v-breadcrumbs>
And then I get this warning in the console. Im not really sure what it means..
default slot' is deprecated, use ':items and scoped slot "item"' instead
If i try the default template from vuetify docs: <v-breadcrumbs :items="items"> it only allows for a href not a :to which is what I need.
Can anyone help me out.

It seems that Veutify now provides an item scoped slot that can be used to customize breadcrumbs. Looking at their example here I think what you need to do is the following ..
<v-breadcrumbs :items="breadcrumbs" divider=">">
<v-breadcrumbs-item
slot="item"
slot-scope="{ item }"
exact
:to="item.to">
{{ item.text }}
</v-breadcrumbs-item>
</v-breadcrumbs>

alternative is use a method with a click event
<template>
<v-breadcrumbs divider=">">
<v-breadcrumbs-item
v-for="breadcrumb in breadcrumbs"
exact
#click="goTo(breadcrumb.to)">
{{ breadcrumb.text }}
</v-breadcrumbs-item>
</v-breadcrumbs>
</template>
<script>
export default {
methods: {
goTo (payload) {
this.$router.push(payload)
}
}
}
</script>

You can use below code which is much simpler compare to the above solutions:
<template>
<v-breadcrumbs :items="breadcrumbs">
<template v-slot:divider>
<v-icon>mdi-menu-right</v-icon>
</template>
</v-breadcrumbs>
</template>
<script>
export default {
data() {
return {
breadcrumbs: [
{
nuxt: true,
activeClass: "",
text: "Page A",
to: { name: "page-a" },
},
{
disabled: true,
text: "Page B",
},
],
};
},
};
</script>

Example from the official website,
<template>
<v-breadcrumbs :items="items">
<template v-slot:item="{ item }">
<v-breadcrumbs-item
:href="item.href"
:disabled="item.disabled"
>
{{ item.text.toUpperCase() }}
</v-breadcrumbs-item>
</template>
</v-breadcrumbs>
</template>

Related

Using Vue multiselect to change Algolia index

I currently have a page where I'm able to switch Algolia indices with this:
<template>
<button #click="selectedIndex = a">List A</button>
<button #click="selectedIndex = b">List B</button>
<A v-if="selectedIndex === a" />
<B v-if="selectedIndex === b" />
</template>
<script>
import A from '#/A.vue';
import B from '#/B.vue';
export default {
components: {
A,
B
},
data() {
return {
selectedIndex: `a_${this.$root.index}`,
query: ''
};
},
computed: {
a() {
return `a_${this.$root.index}`;
},
b() {
return `b_${this.$root.index}`;
}
}
};
</script>
This is in a file called Index.vue. The different indices are in files A.vue and B.vue.
But now I need to be able to do the same content switching using a vue-multiselect in A.vue and B.vue.
Currently in A.vue, I have
<template>
<ais-instant-search
:search-client="searchClient"
:index-name="a"
:routing="routing"
>
<multiselect
v-model="selectedIndex"
:options="switcherOptions"
:searchable="false"
:close-on-select="true"
:show-labels="false"
placeholder="Choose"
>
<template slot="singleLabel" slot-scope="{ option }">
{{ option.text }}
</template>
<template slot="option" slot-scope="{ option }">
{{ option.text }}
</template>
</multiselect>
</ais-instant-search>
</template>
export default {
components: {
Multiselect
},
data() {
searchClient: algoliasearch(window.algolia.id, window.algolia.key),
selectedIndex: { value: 'a', text: 'List A' },
switcherOptions: [
{ value: 'a', text: 'List A' },
{ value: 'b', text: 'List B' }
]
};
},
};
What I don't know how to do now is send the value from the multi-select from A.vue back up to Index.vue where the different indices are defined.
First observation that I have, in your A.vue you are binding variable named a to your index, but do not have a defined in your data, same thing for routing.
What is the point of computed properties a and b, they are just returning strings, with do not do any computing, this could probably be defined in data:
data() {
return {
selectedIndex: 'a_index',
query: '',
a: 'a_index',
b: 'b_index',
};
},
Are A.vue and B.vue identical components? If only bindings are different, you can probably combine them into one component, and just pass different props to them. Hard to know for sure without seeing complete code.
So one way of doing this is emitting events from child to parent components. Documentation reference: https://vuejs.org/guide/essentials/event-handling.html
On your multiselect component add #select="$emit("indexSelected", selectedIndex)"
Like so:
<multiselect
v-model="selectedIndex"
:options="switcherOptions"
:searchable="false"
:close-on-select="true"
:show-labels="false"
placeholder="Choose"
#select="$emit("indexSelected", selectedIndex)"
>
This will emit event with name of indexSelected and included selectedIndex value in its payload.
Then in Index.vue you need to add these event listeners to both A and B Components:
<A v-if="selectedIndex === a" #indexSelected="selectedIndex = $event.value === 'a' ? 'a_index' : 'b_index'" />
<B v-if="selectedIndex === b" #indexSelected="selectedIndex = $event.value === 'a' ? 'a_index' : 'b_index'" />
Or if you would like cleaner template you can create a method:
methods: {
updateSelectedIndex(event){
this.selectedIndex = event.value === 'a' ? 'a_index' : 'b_index';
}
}
And then update template to:
<A v-if="selectedIndex === a" #indexSelected="updateSelectedIndex" />
<B v-if="selectedIndex === b" #indexSelected="updateSelectedIndex" />
EDIT:
I think this is kind of what you are looking for(reading between the lines lol), this rolls Index.vue, A.vue, B.vue into one component, because what you are trying to achieve is a lot simpler this way IMO. Obviously your actual app is more complex, so apply this as needed.
IndexAB.vue would look like this, values replaces with algolia demo, so substitute as needed:
<template>
<div>
<p>
<strong>Changing Index with buttons: </strong>
<button
v-for="option in searchIndexOptions"
:key="option.value"
#click="searchIndexName = option"
>
{{ option.text }}
</button>
</p>
<ais-instant-search
:search-client="searchClient"
:index-name="searchIndexName.value"
>
<p>
<strong>Changing Index with vue-multiselect: </strong>
<VueMultiselect
v-model="searchIndexName"
:options="searchIndexOptions"
:searchable="false"
:close-on-select="true"
track-by="value"
label="text"
placeholder="Change Search Index Here"
>
<template v-slot:singleLabel="{ option }">
<strong>{{ option.text }}</strong>
</template>
<template v-slot:option="{ option }">
<strong>{{ option.text }}</strong>
</template>
</VueMultiselect>
</p>
<ais-search-box />
<ais-hits>
<template v-slot:item="{ item }">
<h2>{{ item.name }}</h2>
</template>
</ais-hits>
</ais-instant-search>
</div>
</template>
<script>
import VueMultiselect from "vue-multiselect";
import algoliasearch from "algoliasearch/lite";
import "instantsearch.css/themes/satellite-min.css";
import "vue-multiselect/dist/vue-multiselect.css";
export default {
name: "IndexAB",
components: { VueMultiselect },
data: () => ({
searchClient: algoliasearch("latency", "6be0576ff61c053d5f9a3225e2a90f76"),
searchIndexName: { value: "instant_search", text: "List A" }, // Defaults to instant_search/List A
searchIndexOptions: [
{ value: "instant_search", text: "List A" },
{ value: "airbnb", text: "List B" },
{ value: "airports", text: "List C" },
],
}),
};
</script>
And sandbox: https://codesandbox.io/s/compassionate-ptolemy-9ljmhh?file=/src/components/IndexAB.vue
I had started with Vue 3 sandbox, so few things will be sligtly different(like import of vue-multiselect, and v-slot syntax)

Vue2 How to use nested <template> tags?

I'm using Vue2's latest version.
I have 2 components; 1st component:
<stack>
<template #first>
<template #cell(details)="row">
{{ row.details ? "Hide" : "Show" }}
</template>
</template>
</stack>
2nd component:
<template>
<div>
<slot name="first"></slot>
</div>
</template>
<script>
export default {
data() {
return {
row: {
name: 'Test',
details: true
}
}
},
}
</script>
I want to simply insert the contents of the <template #first> from the 1st component into the slot in the 2nd component while maintaining everything inside the <template #first> tag.
So the desired outcome would look like this; the slot would be replaced with the contents of the <template #first> tag:
<template>
<div>
<template #cell(details)="row">
{{ row.details ? "Hide" : "Show" }}
</template>
</div>
</template>
<script>
export default {
data() {
return {
row: {
name: 'Test',
details: true
}
}
},
}
</script>
However, the 1st component does not work like this. It says that I cannot have a template inside a template. Is this actually possible what I'm trying to achieve here? If yes, how?

How can I set custom template for item in list and than use it inside `v-for` loop?

What I want to achieve is something like:
<li v-for="(item, index) in items" :key="index>
<div v-if="item.Component">
<item.Component :value="item.value" />
</div>
<div v-else>{{ item.value }}</div>
</li>
But anyway I don't like at all this solution. The idea of defining Component key for an item in items list is hard to maintain since at least it is hard to write it in template-style way (usually we are talking about too long HTML inside). Also I don't like to wrap item.Component inside div.
data() {
return {
list: [{
value: 'abc',
Component: {
props: ['value'],
template: `123 {{ value }} 312`
}
}]
};
}
Does anyone know the best-practice solution for this and where Vue describes such case in their docs?
You can use Vue's <component/> tag to dynamically set your component in your list.
<li v-for="(item, index) in items" :key="index>
<component v-if="item.Component" :is="item.Component" :value="item.value"></component>
<div v-else>{{ item.value }}</div>
</li>
<script>
...,
data: () => ({
list: [{
value: 'abc',
Component: {
props: ['value'],
template: `<div>123 {{ value }} 312</div>` // must be enclosed in a element.
}
}]
})
</script>
You can also import a component too so you can create a new file and put your templates and scripts there.
Parent.vue
<script>
import SomeComponent from "#/components/SomeComponent.vue"; //import your component here.
export default {
data() {
return {
list: [
{
value: "abc",
Component: SomeComponent // define your imported component here.
},
]
};
}
};
</script>
SomeComponent.vue
<template>
<div>123 {{ value }} 312</div>
</template>
<script>
export default {
name: "SomeComponent",
props: ["value"]
};
</script>
Here's a demo.

Change a layout variable value from a page in Nuxt.js

There is something I really dont get about Vue / Nuxt, If I import a component in my /blog/slug.vue I am able to change the variables as I want but how I can do that I want to change something in the /layouts/default.vue ? I am able to do it with the and the by using head() but can I do that with a simple variable like {{ navbar_title }}
For example my /layouts/default.vue look like this :
<template>
<div class="navbar">
{{ navbar_title }}
</div>
</template>
Is it possible to can change {{ navbar_title }} value from a page like /pages/about.vue ?
Please visit code sandbox link
code
in NavBar.vue
<template>
<div>NavBar component {{ title }}</div>
</template>
<script>
export default {
props: {
title : {
type: String,
required: true,
default: 'Website title/ suitable title'
}
}
}
</script>
from page component pages/index.vue
<template>
<section>
<div>
<NavBar :title="title"/>
<h2>Starter for CodeSandBox</h2>
</div>
</section>
</template>
<script>
import NavBar from '~/components/NavBar.vue'
export default {
pageTitle: 'from Home Page',
components: {
NavBar
},
computed: {
title() {
return this.$route.matched.map((r) => {
return r.components.default.options
? r.components.default.options.pageTitle
: r.components.default.pageTitle;
})[0];
}
}
}
</script>

How to get the value with v-select, options loaded from ajax using slot templates

I am trying to get the selected value to update in my vue component, but it doesn't change and stays empty instead, i can select things but i can't do anything with it.
I have tried adding :value to the v-select component, but it just doesn't update the value whenever i select something.
Since i am still trying this with the example from their documentation, i made a fork on codepen here: https://codepen.io/andyftp/pen/GweKpP so you can try it out.
Anyone can help me here?
HTML:
<div id="app">
<h1>Vue Select - Ajax</h1>
<v-select label="name"
:filterable="false"
:options="options"
:selected="selected"
#search="onSearch"
><template slot="no-options">
type to search GitHub repositories..
</template>
<template slot="option" slot-scope="option">
<div class="d-center">
<img :src='option.owner.avatar_url'/>
{{ option.full_name }}
</div>
</template>
<template slot="selected-option" scope="option">
<div class="selected d-center">
<img :src='option.owner.avatar_url'/>
{{ option.full_name }}
</div>
</template>
</v-select>
Selected: {{ selected }}
</div>
JS:
Vue.component("v-select", VueSelect.VueSelect);
new Vue({
el: "#app",
data: {
selected: null, // this needs to be filled with the selected value (id or object), but it stays empty
options: []
},
methods: {
onSearch(search, loading) {
loading(true);
this.search(loading, search, this);
},
search: _.debounce((loading, search, vm) => {
fetch(
`https://api.github.com/search/repositories?q=${escape(search)}`
).then(res => {
res.json().then(json => (vm.options = json.items));
loading(false);
});
}, 350)
}
});