Vuetify - Set active class for submenu item when selected - javascript

I have a Vue/Vuetify app that has a left nav menu, and it was originally created before my time with just a single level of items. I've had to add a second level of menu items, and they work fine to the extent that they expand when the parent item is clicked, and when clicked they do what they should. The thing I can't quite figure out is how to 1) highlight the selected submenu item and 2) remove the highlighting from the parent item when clicked.
Here is the markup for the element:
<template>
<v-list dark class="ap-sidebar-applist">
<v-list-group
class="ap-sidebar-group"
v-for="(item, i) in items"
:key="i"
:prepend-icon="item.icon"
:value="item.visible"
#click="onClick(item)"
>
<v-list-tile slot="activator">
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile>
<div v-if="item.children">
<v-list-tile class="sub-list"
v-for="(subMenu, j) in item.children"
:key="j"
#click="onClick(subMenu, true)"
active-class="default-class sub-list"
>
<v-list-tile-action>
<v-icon>{{ subMenu.icon }}</v-icon>
</v-list-tile-action>
<v-list-tile-title>{{ subMenu.title }}</v-list-tile-title>
</v-list-tile>
</div>
</v-list-group>
<!--</v-list-group> -->
</v-list>
</template>
And here is a full CodePen. One note for the CodePen is that the setCurrentWorkspace called from onClick() is a Vuex action that is used higher up the component tree to highlight menu tabs elsewhere in the app.
What I'm seeing is that the sub-class class (defined in active-class for the child items) is applied to both of the submenu items when the parent Templates item is selected, and the v-list__group__header--active class remains on the parent item as well.
Do I need to manually remove the active class from the parent Templates item, and also remove it manually from the other submenu item? Or is there an easier way to do this with the current Vuetify API?

Related

don't expand v-list-group if click on v-checkbox

I have an expandable v-list-group with a v-checkbox where when i click on the v-checkbox the list toggles. I want to disable this reaction. it is possible? my code element:
<v-list>
<v-list-group>
<template v-slot:activator>
<v-list-item-action>
<v-checkbox #click="fn()"/>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title/>
</v-list-item-content>
</template>
...
</v-list-group>
</v-list>
Thanks.
Try using click.stop on the v-checkbox in order to stop click event propagation.
Reference: https://v3.vuejs.org/api/directives.html#v-on
Similar question: Vutify list group make parent clickable

Only make the buttons inside v-list clickable, while disabling the v-list-item content

I'm using a v-list component to show available bundles of a product. Basically, I want to be able to press a button in the v-list to remove this bundle (the item on the row of the v-list).
Clicking on the button works fine, but the entire v-list-content is clickable. Even tho it does nothing, I want to disable it so that the user can only click on the button to the right of every v-list-item. Is there a way to do that?
I'm aware that I can add the props disabled to the v-list tag. However, every child tags of the v-list are disabled, so the button becomes unclickable.
<v-list rounded> <!-- disabled -->
<v-list-item-group
v-model="selectedItem"
color="primary"
>
<v-list-item
v-for="(bundle, i) in editForm.suggested_bundles"
:key="i"
>
<v-list-item-content append-icon="mdi-delete">
<v-list-item-title v-text="bundle"></v-list-item-title>
</v-list-item-content>
<v-list-item-icon>
<v-btn #click="removeBundle(editForm.suggested_bundles, bundle)">
<v-icon small>mdi-delete</v-icon>
</v-btn>
</v-list-item-icon>
</v-list-item>
</v-list-item-group>
</v-list>
Any solution for this?
Thanks in advance!
Looks to me that you don't perhaps need the v-list-item-group, so by removing that, only your button is clickable:
<v-list-item v-for="(bundle, i) in editForm.suggested_bundles" :key="i">
<v-list-item-content append-icon="mdi-delete">
<v-list-item-title v-text="bundle"></v-list-item-title>
</v-list-item-content>
<v-list-item-icon >
<v-btn #click="removeBundle(editForm.suggested_bundles[i])">
<v-icon small>mdi-delete</v-icon>
</v-btn>
</v-list-item-icon>
</v-list-item>
If you need to use selectedItem you can always (re)assign the value in removeBundle function. Hopefully this solution will suit your needs.
DEMO for reference

Vue Navigation Drawer

I am utilizing a v-navigation-drawer with the expand-on-hover prop. When it is in its mini variant, I would like to hide the textbox and button at the bottom. The navigation drawer has computed properties, one of which is isMiniVariant. Set to true when collapsed and false when expanded. How can I use this property to bind a style to the div that contains the items I would like to hide?
The codepen/code can be seen below:
https://codepen.io/emicion/pen/zYqerGo?editors=1000
<div id="app">
<v-app id="inspire">
<v-navigation-drawer permanent left app expand-on-hover dark>
<v-list-item>
<v-list-item-icon>
<v-icon>mdi-message</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title class="title">Application</v-list-item-title>
<v-list-item-subtitle>subtext</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
<v-divider></v-divider>
<template v-slot:append>
<!-- I want to hide all of this below -->
<div class="pa-2">
<v-textarea no-resize outlined placeholder="Enter comment here..." rows="2"></v-textarea>
<v-btn dark outlined small>
<span>Add Comment</span>
</v-btn>
</div>
</template>
</v-navigation-drawer>
</v-app>
</div>
Computed properties listed on VNavigationDrawer
One way is:
add to style
.v-navigation-drawer--mini-variant .hideme {
display:none;
}
add class to the div you want to hide
<div class="pa-2 hideme">
Actually, the better way is to add v-list-group--sub-group to the class of the div
<div class="pa-2 v-list-group--sub-group">
Both are kind of hacky, but I've tried using v-list-group's directly, but it's not easy

enable router calls on el-submenus in Element-UI

I'm trying to set up a Navbar in Element-UI with a nested submenu. In additions to opening the submenu, I want the router to go to the index attribute of the submenu. This doesn't happen; clicking on a submenu doesn't activate the router - it only works for el-menu-item and not el-submenu, as far as I can tell.
Here's my code:
<el-submenu index="2">
<template slot="title"><feather type="edit"></feather></template>
<el-submenu :index="subject.label" v-for="subject in subjects">
<template #click="setSubject(subject.label)" slot="title">{{ subject.label }}</template>
<el-submenu :index="spec.label" v-for="spec in subject.children">
<template slot="title">{{ spec.label }}</template>
<el-menu-item :index="prac.label" v-for="prac in spec.children">{{ prac.label }}</el-menu-item>
</el-submenu>
</el-submenu>
</el-menu-item>
I tried adding a click event to <el-submenu :index="subject.label" v-for="subject in subjects">'s template called setSubject. It fails to execute when clicked. Can anyone help me figure this out?

What is the purpose of <template> usage in Vuetify?

I want to use Vuetify 2.0 in my project and currently reading about v-stepper component which is used to display progress through numbered steps.
In the playground example provided I see that they are using <template> element to wrap content of v-stepper component. HTML looks something like this (note: I removed unnecessary details):
<v-stepper>
<template v-for="n in steps">
<v-stepper-content
:key="`${n}-content`"
:step="n"
>
</v-stepper-content>
</template>
</v-stepper>
Notice the <template> tag used. What is the purpose of it? When should I use it as opposed to just putting the <v-stepper-content> directly inside of <v-stepper>?
I've read a bit about element on MDN but I am not sure how to use it specifically with Vuetify (or more generally with Vue.Js or just pure HTML/CSS/JS for that matter).
a <template> in the context of a v-for loop is an organizational item.
It does not get rendered by the browser. It is there to help with more complex rendering situations, where you don't want to limit yourself to a single element
In most cases you have a pretty straight forward mapping of items, each item in an array gets a <li> element. If this is the case, you're not likely to use this.
Here is an example of a problem where it might help...
Let's say you want to loop through an array of objects, and render a v-btn if the object is a button, and a v-image if the object is an image.
without template...
<span v-for="item in items">
<v-btn v-if="item.isBtn"></v-btn>
<v-img v-else-if="item.isImg"></v-img>
</span>
The problem is that each item will be wrapped in the span.
<span>
<v-btn/>
</span>
<span>
<v-img/>
</span>
<span>
<v-btn/>
</span>
If you, however, use the template element, the wrapping element is no longer there.
<template v-for="item in items">
<v-btn v-if="item.isBtn"></v-btn>
<v-img v-else-if="item.isImg"></v-img>
</template>
and you will get...
<v-btn/>
<v-img/>
<v-btn/>
You can also have it return multiple items in one instance of the loop.
in the vue docs at https://v2.vuejs.org/v2/guide/list.html#v-for-on-a-lt-template-gt
it shows an example of rendering more than one item per iteration:
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
There are some other cases where this might be helpful but not likely something you come across on a daily basis.
TL;DR;
Vue doesn't render the <template> element. It helps organize code chunk without the need of a single child element when looping
part 2.
When should I use it as opposed to just putting the directly inside of ?
Because the structure of vertical and horizontal steppers is different, the vuetify authors used it in the playground to allow users to toggle it. The first level of template (<template v-if="vertical">) is used do determine whether the next level should render the v-stepper-step elements as vertical or as horizontal. The second level is used to do the iterating of items.
example:
vertical (step and content are siblings):
<template>
<v-stepper v-model="e6" vertical>
<v-stepper-step :complete="e6 > 1" step="1">
Select an app
<small>Summarize if needed</small>
</v-stepper-step>
<v-stepper-content step="1">
<v-card color="grey lighten-1" class="mb-12" height="200px"></v-card>
<v-btn color="primary" #click="e6 = 2">Continue</v-btn>
<v-btn text>Cancel</v-btn>
</v-stepper-content>
<v-stepper-content step="2">...</v-stepper-content>
<v-stepper-step :complete="e6 > 3" step="3">...</v-stepper-step>
</v-stepper>
</template>
horizontal (each step is separate):
<template>
<div>
<v-stepper>
<v-stepper-header>
<v-stepper-step step="1">Select campaign settings</v-stepper-step>
<v-divider></v-divider>
<v-stepper-step step="2">Create an ad group</v-stepper-step>
<v-divider></v-divider>
<v-stepper-step step="3">Create an ad</v-stepper-step>
</v-stepper-header>
</v-stepper>
<v-stepper value="2" class="mt-12">
...
</v-stepper>
<v-stepper value="3" class="mt-12">
...
</v-stepper>
</div>
</template>

Categories

Resources