Adding active class :click - vue.js

I am having trouble adding an active class when clicking a link.
I have the dynamic class setup with a click listener that passes an argument to the function but the class does not update. I am not sure why. The 'Dashboard' link is red when page is refreshed so I know it is working to an extent.
<template>
<b-list-group>
<b-list-group-item
v-for="(link, index) in menu"
:key="index"
:href="link.sectionId"
:class="{active: link.title === selectedLink}"
:click="isActive(link.title)"
>
{{link.title}}
</b-list-group-item>
</b-list-group>
</template>
<script>
export default {
data() {
return {
selectedLink: 'Dashboard',
menu: [
{
title: 'Dashboard',
icon: labStuffs,
sectionId: '#'
},
{
title: 'Lactose intolerance',
icon: labStuffs,
sectionId: '#'
}
]
}
},
methods: {
isActive(title) {
this.selectedLink === title
}
}
}
</script>
<style scoped lang="scss">
.active {
background-color: red;
}
</style>
Expecting the background colour of clicked link to change. Only the dashboard link is red and whenever I click anything else, nothing happens.

Here is a working example of your code.
I changed the :click to #click and the following.
methods: {
isActive(title) {
this.selectedLink = title // Had === before
}
}
https://codesandbox.io/s/vue-template-y3k12?fontsize=14

Related

Vue El-Select doesn't work as expected while passing value from parent to child using watch

Component A
<el-select v-model="value" placeholder="Select Action" #change="updateDropdowns($event)" prop="action">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
<tableview
:action="this.value"
v-show="false">
</tableview>
<script>
export default {
name: 'warehouseAdd',
components: {
tableview
},
props: [
'component'
],
data() {
return {
options: [
{
value: 'add',
label: 'Add'
}, {
value: 'edit',
label: 'Edit'
}
],
value: '',
Component B
<script>
props: [
'action'
],
watch: {
'action': function (value) {
console.log(value);
//Select value from dropdown doesn't pass the value at 1st attempt.
//If I again select the value from dropdown then I get the value.
}
}
Here whenever I try to get value.. I am unable to get value on first event. I need value once I select value from dropdown. I might be doing something wrong not exactly sure.. new to VueJs.
Please let me know how do I pass value at 1st instance to Component B.
Although I am getting the value in Component A on first attempt just not getting at Component B
I am able to fetch dropdown value in parent component but unable to fetch the same in child component when I initially select the value for 1st time. When I change the value of dropdown 2nd time then I get the value in child component.
Thanks!
In your question title you said that El-Select doesn't work as expected. Actually it works as expected. When you reload the page, all Vue data come back to their initial values. So when you set value: '' in component A (that I called it parentTable in my following codes), then after reloading the page the value of '' comes back to that value data. If you want to store the value of selected item before reloading page, there are some solutions to that. One of them is using Window localStorage. Here is the codes that works for me:
parentTable.vue component:
<template>
<div>
<el-select v-model="value" placeholder="Select Action">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
<tableview
:action="this.value"
v-show="false">
</tableview>
</div>
</template>
<script>
import tableview from "./tableview";
export default {
name: "parentTable",
components: {
tableview
},
data() {
return {
options: [
{
value: 'add',
label: 'Add'
}, {
value: 'edit',
label: 'Edit'
}
],
value: null,
}
},
watch: {
value: function (newVal) {
this.getValueOf(newVal);
}
},
methods: {
getValueOf: function (storeValue) {
localStorage.setItem("option", storeValue);
}
},
mounted() {
/* Here we get the previous selected item from localStorage */
this.value = localStorage.getItem("option");
}
}
</script>
<style scoped>
</style>
tableview.vue component:
<template>
</template>
<script>
export default {
name: "tableview",
props: [
'action'
],
watch: {
action: function (value) {
console.log(value);
}
}
}
</script>
<style scoped>
</style>

Stopping an animation with an click event in Vuejs?

I have a MainMenuItem that has a bunch of static titles. There is one variable item that is for news and events and that has a horizontal ticker, scroll animation on it. This animation is happening inside of the MainMenuItem component, but the click event will be happening from the parent. The click event currently needs to stop the animation and change the font weight (can be seen in the readLink class).
Wth Vue I cannot mutate the prop type itself with something like #click="itemType = ''".
So how can I turn this ticker animation off on click?
Basically, all I would need to do is make the MainMenuItem's itemType = '' and make it the same as every other item. Do I need to make a data type? Or a click event that $emit's an event to the child/base component MainMenuItem?
If there is anymore code that is necessary please let me know!
Cheers!
MainMenuItem.vue (base component with the ticker animation )
<template>
<q-btn align="left" dense flat class="main-menu-item" v-on="$listeners">
<div class="flex no-wrap items-center full-width">
<iconz v-if="iconz" :name="iconz" type="pop" color="black" class="mr-md" />
<q-icon :name="menuIcon" />
<div v-if="itemType === 'news'" class="_ticker">
<div class="ellipsis _ticker-item">{{ title }}</div>
</div>
<div v-else>
<div class="ellipsis">{{ title }}</div>
</div>
<q-icon name="keyboard_arrow_right" class="_right-side" />
</div>
</q-btn>
</template>
<style lang="sass" scoped>
// $
.main-menu-item
display: block
font-size: 15px
position: relative
width: 100%
border-bottom: 1px solid #F5F5F5
+py(10px)
._left-side
color: #000000
._ticker
font-weight: bold
margin-left: 2em
width: 83%
white-space: nowrap
overflow: hidden
position: absolute
&-item
display: inline-block
padding-left: 100%
animation: ticker 8s linear infinite
#keyframes ticker
to
transform: translateX(-100%)
</style>
<script>
import { iconz } from 'vue-iconz'
export default {
name: 'MainMenuItem',
components: { iconz },
props: {
comingSoonShow: { type: Boolean, default: false },
title: { type: String, default: 'menu' },
subtitle: { type: String, default: '' },
menuIcon: { type: String, default: '' },
iconz: { type: String, default: '' },
itemType: { type: String, default: '' },
}
}
</script>
MainMenu.vue (just the location I am using the base component)
<template>
<MainMenuItem
v-for="news in newsList"
:key="news.id"
#click="openNews(news)"
:title="news.title"
itemType="news"
:class="{ readLink: readNewsList[news.id] }"
menuIcon="contactless"
></MainMenuItem>
</template>
export default {
name: 'MainMenu',
methods: {
openNews(postInfo) {
dbAuthUser().merge({ seenNewsPosts: { [postInfo.id]: true } })
Browser.open({ url: postInfo.url, presentationStyle: 'popover' })
}
},
computed: {
readNewsList() {
return this.authUserInfo?.seenNewsPosts || {}
},
}
<style lang="sass" scoped>
.readLink
font-weight: 500
</style>
Since it's a prop the simplest way is to emit an event that executes what you need in the parent and also bind a variable not static prop to be able to change it. example in the child :
<button #click="onClickButton">stop animation </button>
export default {
methods: {
onClickButton (event) {
this.$emit('stopAnimation')
}
}
}
And in the parent you listen to it as so:
<MainMenuItem
v-for="news in newsList"
:key="news.id"
#click="openNews(news)"
:title="news.title"
:itemType="itemType"
:class="{ readLink: readNewsList[news.id] }"
menuIcon="contactless"
v-on:stopAnimation="itemType = ''"
></MainMenuItem>
export default {
data() {
return {
itemType: "news",
}
}
}
}

#click not firing on header links for vue.js

I want to change a masthead text to the current route name that I am on. It only works on component mount, and does not fire on click. How do I get the changeHeaderTitle to run from the button click created by the router?
<template>
<div>
<nav class="navigation--navbar">
<router-link
class="navigation--links"
v-for="routes in links"
v-bind:key="routes.id"
#click='changeHeaderTitle'
:to="`${routes.page}`"
>{{routes.text}}</router-link>
</nav>
<div class="header--headline">
<h2 class="header--headline-text">{{headerTitle}}</h2>
</div>
</div>
</template>
<script>
export default {
name: 'Navigation',
data () {
return {
headerTitle: 'Boop',
links: [
{
id: 0,
text: 'Home',
page: '/Home'
},
{
id: 1,
text: 'Tutoring',
page: '/Tutoring'
}
]
}
},
methods: {
changeHeaderTitle: function () {
if (this.$route.path === '/') {
this.headerTitle = 'Home Header Here'
} else {
let routeName = this.$route.path.split('/')
this.headerTitle = routeName[1]
}
}
},
mounted: function () {
this.changeHeaderTitle()
}
}
</script>
Looks like you need to add .native modifier. Do:
<router-link
class="navigation--links"
v-for="routes in links"
v-bind:key="routes.id"
#click.native='changeHeaderTitle'
:to="`${routes.page}`"
>
{{routes.text}}
</router-link>

Kendo-UI Edit template not working with Vue Template Single File Component

I am using kendoui grid vue wrapper, I find out at kendoui vue documentation that I can use a single file Component for kendo templates, I am working on a editable grid with a popup editor, what I am doing is setting the property "editable" with the name of the method that return the template and template args, the same thing as the documentation of Vue Templates of KendoUi, but It just ignore the function and get inline editable.
The other way that I tried is to set the editable property like "{mode: 'popup', template: templateMethod}", and it popup the editing window, but at the content it just displays "[object] [object]".
Here is my Code:
RouterComponent:
<template>
<c-main>
<c-row>
<c-col xs="24" sm="8">
<c-panel title="Departamento<small>Workflow</small>" style="height:350px;">
<div class="u-mt-10"><strong>Nombre</strong></div>
<div class="u-mt-10">{{ $route.params.name }}</div>
<div class="u-mt-10"><strong>Descripción</strong></div>
<div class="u-mt-10">{{ $route.params.description }}</div>
</c-panel>
</c-col>
<c-col xs="24" sm="16">
<c-panel title="Usuarios<small>Administrar</small>" style="height:350px;">
<kendo-datasource
ref="usersdatasource"
:type="'aspnetmvc-ajax'"
:pageSize="20"
:server-filtering='true'
:transport-read-url= "baseServiceUrl+'/api/DepartmentUsers'"
:transport-read-type="'GET'"
:transport-read-data-type="'json'"
:transport-read-data="dataParameters"
:transport-destroy-url="baseServiceUrl+'/api/DepartmentUsers'"
:transport-create-url="baseServiceUrl+'/api/DepartmentUsers'"
:schema-data= "'Data'"
:schema-total= "'Total'"
:schema-errors= "'Errors'"
:schema-model-id="'Id'"
:schema-model-fields="usersSchemaModelFields"
></kendo-datasource>
<kendo-grid
id="usersdatagrid"
:height="'auto'"
:dataSourceRef="'usersdatasource'"
:toolbar="[ {name:'create', text: 'Agregar Usuario'}]"
:groupable='false'
:sortable='true'
:filterable='true'
:selectable='true'
:editable="{ mode: 'popup', template: popupTemplate }"
:pageable-refresh='true'
:pageable-page-sizes='true'
:pageable-button-count="5"
>
<kendo-grid-column
field="UserName"
title="Usuario"
>
</kendo-grid-column>
<kendo-grid-column
field="DisplayName"
title="Nombre"
>
</kendo-grid-column>
<kendo-grid-column
:width="150"
:command="[{name:'destroy', text:'Eliminar' }]" title="Acción">
</kendo-grid-column>
</kendo-grid>
</c-panel>
</c-col>
</c-row>
<c-row>
<c-col xs="24">
<c-panel title="Reglas<small>Departamento</small>" style="height:400px;">
<kendo-datasource
ref="rulesdatasource"
:type="'aspnetmvc-ajax'"
:pageSize="20"
:server-filtering='true'
:transport-read-url= "baseServiceUrl+'/api/Departments'"
:transport-read-type="'GET'"
:transport-read-data-type="'json'"
:transport-update-url="baseServiceUrl+'/api/Departments'"
:transport-update-type="'PUT'"
:transport-update-data-type="'json'"
:transport-destroy-url="baseServiceUrl+'/api/Departments'"
:transport-create-url="baseServiceUrl+'/api/Departments'"
:schema-data= "'Data'"
:schema-total= "'Total'"
:schema-errors= "'Errors'"
:schema-model-id="'Id'"
></kendo-datasource>
<kendo-grid
id="rulesdatagrid"
:height="'auto'"
:dataSourceRef="'rulesdatasource'"
:groupable='false'
:sortable='true'
:filterable='true'
:selectable='true'
:pageable-refresh='true'
:pageable-page-sizes='true'
:pageable-button-count="5"
>
<kendo-grid-column
field="UserName"
title="Usuario"
>
</kendo-grid-column>
<kendo-grid-column
field="Nombre"
title="DisplayName"
>
</kendo-grid-column>
</kendo-grid>
</c-panel>
</c-col>
</c-row>
</c-main>
</template>
<script>
import Vue from 'vue'
import UserTemplateVue from './departmentUserTemplate.vue'
var UserTemplate = Vue.component(UserTemplateVue.name, UserTemplateVue)
export default {
name: "AddUserDepartmentView",
data() {
return {
baseServiceUrl: window.baseServiceUrl,
dataParameters: {
department: $route.params.Id,
roles: "WORKFLOW;WORKFLOWADMIN"
},
filterConfiguration: [],
usersSchemaModelFields: {
Id: { editable: false, nullable: true },
DisplayName: { validation: { required: true } },
UserName: { validation: { required: true } },
Email: { validation: { required: true } },
TenantId: { validation: { required: true } },
IsAdmin: { validation: { required: true } }
}
}
},
methods: {
popupTemplate: function(e) {
return {
template: UserTemplate,
templateArgs: e
}
}
}
};
</script>
<style>
#usersdatagrid{
height:100% !important;
}
#rulesdatagrid{
height:100% !important;
}
</style>
Template Component:
<template>
<span>
<button #click="buttonClick">Click Me</button>
</span>
</template>
<script>
export default {
name: 'template1',
methods: {
buttonClick: function (e) {
alert("Button click")
}
},
data () {
return {
templateArgs: {}
}
}
}
</script>
Please Help me With this.
Thank You a lot
I know this is old, but I stumbled across this while looking for something related, so I thought I'd take a stab at it for future reference.
Two things I would suggest trying here:
Make sure that your component has a name specified.
Try using: editable-mode="popup;" along with editable-template="popupTemplate"
That did the trick for me. For whatever reason, it just wasn't happy when I was passing an object into editable.
Hope that helps!

VueJS: #click.native.stop = "" possible?

I have several nested components on the page with parents component having #click.native implementation. Therefore when I click on the area occupied by a child component (living inside parent), both click actions executed (parent and all nested children) for example
<products>
<product-details>
<slide-show>
<media-manager>
<modal-dialog>
<product-details>
<slide-show>
<media-manager>
<modal-dialog>
</products>
So I have a list of multiple products, and when I click on "canvas" belonging to modal dialog - I also get #click.native fired on product-details to which modal-dialog belongs. Would be nice to have something like #click.native.stop="code", is this possible?
Right now I have to do this:
#click.native="clickHandler"
and then
methods: {
clickHandler(e) {
e.stopPropagation();
console.log(e);
}
code
<template>
<div class="media-manager">
<div v-if="!getMedia">
<h1>When you're ready please upload a new image</h1>
<a href="#"
class="btn btn--diagonal btn--orange"
#click="upload=true">Upload Here</a>
</div>
<img :src="getMedia.media_url"
#click="upload=true"
v-if="getMedia">
<br>
<a class="arrow-btn"
#click="upload=true"
v-if="getMedia">Add more images</a>
<!-- use the modal component, pass in the prop -->
<ModalDialog
v-if="upload"
#click.native="clickHandler"
#close="upload=false">
<h3 slot="header">Upload Images</h3>
<p slot="body">Hello World</p>
</ModalDialog>
</div>
</template>
<script>
import ModalDialog from '#/components/common/ModalDialog';
export default {
components: {
ModalDialog,
},
props: {
files: {
default: () => [],
type: Array,
},
},
data() {
return {
upload: false,
}
},
computed: {
/**
* Obtain single image from the media array
*/
getMedia() {
const [
media,
] = this.files;
return media;
},
},
methods: {
clickHandler(e) {
e.stopPropagation();
console.log(e);
}
}
};
</script>
<style lang="scss" scoped>
.media-manager img {
max-width: 100%;
height: auto;
}
a {
cursor: pointer;
}
</style>
Did you check the manual? https://v2.vuejs.org/v2/guide/events.html
There is #click.stop="" or #click.stop.prevent=""
So you don't need to use this
methods: {
clickHandler(e) {
e.stopPropagation();
console.log(e);
}
}
In the Vue, modifiers can be chained. So, you are free to use modifiers like this:
#click.native.prevent or #click.stop.prevent
<my-component #click.native.prevent="doSomething"></my-component>
Check events
I had the same problem. I fixed the issue by using following:
<MyComponent #click.native.prevent="myFunction(params)" />