How to remove vuetify card automatically after a few seconds - javascript

I have a vue card on which I am dsiplaying a success message. I have a functionality according to which, if the user clicks the ok button, the card disappears. Apart from that I also want it to disappear automatically after a few seconds even if the button is not clicked. How can I do that? Here is my component:
<template>
<div v-if="show" class="notifications">
<div class="globalSuccessWrapper">
<v-layout>
<v-flex xs12 sm6 offset-sm3>
<v-card flat color="green">
<v-card-title primary-title>
<div>
<h3 class="headline">Neu Benutzer angelegt</h3>
<div>{{ card_text }}</div>
</div>
</v-card-title>
<v-card-actions>
<div class="close"><v-btn #click="removeMessage(0)">Ok</v-btn></div>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</div>
</div>
</template>
<script>
export default {
data() {
return {
card_text: 'Success!',
show: true,
notificationsToDisplay: [],
graphQLNotifications: [],
};
},
methods: {
removeMessage(seconds, timeout) {
if (!timeout) {
setTimeout(() => {
this.show = false;
}, seconds * 1000);
} else {
timeout(seconds);
}
},
},
};
</script>
<style scoped lang="scss">
.globalSuccessWrapper {
position: absolute;
z-index: 10000;
width: 100%;
}
</style>
I want to add this functionality in removeMessage in the else case under timeout

You can't do it from removeMessage, because you want it to happen without pressing the button.
You should watch for changes on the data.show. Details on how to do this here.
Inside the watch when the value is set to true you can set a timeout and save the identifier returned by setTimeout. The timeout should set data.save to false, this will close the notification. You also need to clear the timeout from inside removeMessage or from inside the watch method when the value becomes false.
You need to clear the timeout when the notification is closed to prevent the following behaviour:
a notification is opened
the user taps the close button
another notification is opened, during the close timeout
the timeout fires and the second notification is closed prematurely

Related

Vue mouseover not causing changes to the data

I am trying to attach a v-mouseover directive to a bootstrap Vue element b-list-group-item as shown below.
<b-row>
<b-col cols="3">
<b-list-group>
<b-list-group-item :active="register"
#click="switchRegister" button
#mouseover="isRegisterHover = true"
#mouseleave="isRegisterHover = false"
class="border-0 bg-transparent register"> Register </b-list-group-item>
</b-list-group>
</b-col>
<b-col cols="9">
<div id="action-screen-canvas-register v-if="isRegisterHover"> </div>
</b-col>
</b-row>
The variable isRegisterHover is tied to the boolean value in the data which determines whether or not the div will be shown.
export default {
name: 'Home',
components: {
Navi
},
data() {
return {
isRegisterHover: false,
// ...
}
},
// ...
}
Thing is that the action-canvas-register div remains hidden when I hover the item, Vue devtool also shows that the data remains unchanged when I mouseover them. How do I make the isRegisterHover value change when I mouse-over the item?
You could also do this with pure CSS if you wanted to. You could do something like:
<template>
<div id="target">Hover this</div>
<div>...</div> // This will be hidden when #target is hovered
</template>
<script>
...
</script>
<style>
#target:hover + div {
visibility: hidden; // Hides the element like v-show
or
display: none; // Hides the element like v-if
}
</style>
Your code should work. See this:
I would recommend using v-show instead of v-if. See this.
<script>
export default {
data() {
return {
isRegisterHover: false
}
}
}
</script>
<template>
<div #mouseover="isRegisterHover = true"
#mouseleave="isRegisterHover = false">Hover this</div>
<div v-show="isRegisterHover">This will show/hide (v-show)</div>
<div v-if="isRegisterHover">This will show/hide (v-if)</div>
</template>

VUE: Disable buttons until animation ends

how to prevent click when animation is in progress with VUE?
<button v-model="show" #click="show === 'showFirst'">click me first</button>
<button v-model="show" #click="show === 'showSecond'">click me second</button>
<transition :enter-active-class="'animated fadeIn'" :leave-active-class="'animated fadeOut'">
<div class="first" key="1" v-if="showFirst">First Div</div>
<div class="second" key="2" v-if="showSecond">Second Div</div>
</transition>
VUE
export default {
data: function() {
return: {
show: "showFirst"
}
}
}
After clicking on the first button, both will be deactivated until the animation ends. Is it possible either in this way or in another way?
Now when I click both buttons alternately, the animations interrupt each other.
You can use <transition></transition> JS hooks.(https://v2.vuejs.org/v2/guide/transitions.html#JavaScript-Hooks)
<transition #before-enter="disabled=true" #after-leave="disabled=false">
<div class="first" key="1" v-if="showFirst">First Div</div>
<div class="second" key="2" v-if="showSecond">Second Div</div>
</transition>
listen to transition end with vanilla js
const transition = document.querySelector('.transition');
transition.addEventListener('transitionend', () => {
console.log('Transition ended');
});
There are some things I don't really get in your code though. Like why the buttons have v-models. What are you trying to perform two-way data binding for? I think just having the buttons trigger events is enough.
And why your click events are comparing and not assigning.
You could use the disabled prop for the buttons too, so they're disabled respective to a boolean you're manipulating.
So probably it should be something like this:
<button #click="isActivated" :disabled="!isEnabled">click me first</button>
<button #click="isActivated" :disabled="!isEnabled">click me second</button>
<transition :enter-active-class="'animated fadeIn'" :leave-active-class="'animated fadeOut'">
<div class="first" key="1" v-if="show === 'showFirst'">First Div</div>
<div class="second" key="2" v-if="show === 'showSecond'">Second Div</div>
</transition>
Then depending on the timing of your animations, you can have a disabled function that you pass as a prop to the button element.
Like this
data() {
return {
show: 'showFirst',
isEnabled: true,
}
},
methods: {
isActivated(){
//first starts off as false
this.show === 'showFirst' ? this.show = 'showSecond' : this.show = 'showFirst'
this.disableButtons();
},
disableButtons(){
//disable the button then enable after the number of seconds of the animation
this.isEnabled = false
setTimeout(() => {
this.isEnabled = true
}, noOfSecondsOfAnimation)
}
}

How can i listen for an event from a sub component in vue?

I have 3 components
Stage
StageComponent
StageElementComponent
the Stage contains the default data and the basic control of all 3 components.
the StageComponent i filter the StageElementComponent elements, and have some design, validations and user interactions in it.
the StageElementComponent display and element based on the user choise.
Things to take in account
I want to know if it is possible to emit an event from StageElementComponent and listen to it in the Stage component? like
<template>
//StageElementComponent
<div class="element d-flex flex-column justify-content-center"
#dblclick="clear">
<i class="material-icons" v-if="element" :class="[`bg-${element.type.color}`]">{{ element.type.icon }}</i>
</div>
</template>
<script>
export default {
props : {
element : {
type : Object,
required : true
}
},
methods : {
clear : function($event) {
this.$emit('clear', {
index : this.element.index
})
}
}
}
</script>
<style scoped lang="scss">
.element {
cursor: pointer;
}
</style>
and in the Stage component listen to it like
<v-stage id="ticktr" class="section center"
:rows="height"
:columns="width"
:elements="elements"
#clear="clearElement"></v-stage>
I do need these 3 components.
I don't want to listen and emit in the StageComponent as i would be repeating myself
I don't want to use $root.$emit.
It is possible to do this? how?

Polymer iron-list not updating view on dynamic add

I am using Polymer 1.7.0 and Angular2 to build a app. I created a custom Polymer element to wrap the iron-list template in order to be able to use it with Angular2 but i have a problem when it comes to dynamicly adding items to the iron-list.
The add function modifies the items array but it doesnt render the new element even if i am triggering the iron-resize event after modifying the items array.
If i delete a item first, and then try to add a element, then it gets rendered.
This is the polymer element i use:
<!--.... dependencies imports .... -->
<dom-module id="role-users-list">
<template>
<style is="custom-style" include="iron-flex iron-flex-alignment custom-layout-classes">
:host {
display: block;
}
</style>
<iron-media-query query="(min-width: 600px)" on-query-matches-changed="queryValueChanged" query-matches="{{wide}}"></iron-media-query>
<iron-list items="{{items}}" class="test" style="height:85%">
<template>
<paper-card class="verticalJustified">
<div class="horizontalJustified">
<div class="card-content horizontalJustified">
<paper-icon-button class="cardIcons" icon="group-work"></paper-icon-button>
<div class="verticalStart">
<span class="cardTitle">{{item.fullName}}</span>
<template is="dom-if" if="{{item.direct}}">
<span class="cardSubTitle">User associated directly </span>
</template>
<template is="dom-if" if="{{!item.direct}}">
<span class="cardSubTitle">Role granted through {{item.groupName}} </span>
</template>
</div>
</div>
<template is="dom-if" if="{{item.direct}}">
<div class="horizontalJustified">
<paper-icon-button class="cardIcons" icon="delete" target-user="{{item.username}}" on-tap="onDelete" (click)="deleteUser(user)"></paper-icon-button>
</div>
</template>
</div>
</paper-card>
</template>
</iron-list>
</template>
<script>
Polymer({
is: 'role-users-list',
onDelete: function(e){
this.fire("deleteTrigger",{data:e.model.item});
},
queryValueChanged: function(e){
this.fire("mediaQueryTrigger",{data: e.detail.value})
},
updateIronList:function(){
this._nodes.filter(function(value){return value.localName === "iron-list"})[0].fire("iron-resize");
},
focusElem:function(){
var test = this._nodes.filter(function(value){return value.localName === "iron-list"})[0];
test.selectItem(this.items[0]);
},
properties: {
items: {
type: Array,
notify: true,
value:[],
}
}
});
</script>
</dom-module>
After adding or removing a element i call the updateIronList function to trigger the rendering with the iron-resize event.
PS: The add functionality is in the parent Angular2 component where i modify the items array.
The only difference i could notice was that since the delete button is inside the polymer custom element, it causes it to focus that item when its clicked.
If i didnt make myself understood, ask and i will clarify.
I fixed my issue by updating the updateIronList function to:
updateIronList:function(){
let ironListElem = this._nodes.filter(function(value){return value.localName === "iron-list"})[0];
ironListElem.fire("iron-resize");
ironListElem._virtualCount = (this.items.length <= 20) ? this.items.length : 20;
},
It seems the issue was caused by the fact that when the items array length changed, iron-list didnt automaticly update the number of items displayed.

How to cancel a core-toolbar on-tap event when clicking on a paper-tab inside the toolbar

When I click on the space above the paper-tabs in waterfall-tall mode I want to trigger a home function.
<core-header-panel mode="waterfall-tall">
<core-toolbar class="animate" id="core_bar" on-tap={{home}}>
<paper-tabs selected="0" self-end id="paper_tabs">
<paper-tab>0</paper-tab>
<paper-tab>1</paper-tab>
<paper-tab>2</paper-tab>
<paper-tab>3</paper-tab>
</paper-tabs>
</core-toolbar>
<core-animated-pages transitions="slide-from-right" selected="{{ $.paper_tabs.selected }}" id="core_pages">
<section></section>
<section></section>
<section></section>
<section></section>
<section>My home</section>
</core-animated-pages>
</core-header-panel>
This triggers the home function but when I click on a paper tab the home function gets called also. How can I cancel the home function when I click on a paper tab?
<script>
Polymer('my-pages', {
home:function(){
this.$.paper_tabs.selected=4
}
});
</script>
You could do it like this:
home: function(e) {
// make sure this tap was on the core-toolbar itself
if (e.target.localName === 'core-toolbar') {
this.$.paper_tabs.selected = 4;
}
}
However, referring to $.paper_tabs this way is not a good practice. Instead, decide that your my-pages has a property for activePage and bind the UI elements to that property. This way your logic and your template UI are loosely coupled.
...
<template>
...
<paper-tabs selected="{{activePage}}" self-end>
...
<core-animated-pages selected="{{activePage}}" transitions="slide-from-right">
...
</template>
<script>
Polymer({
activePage: 0,
home: function(e) {
if (e.target.localName === 'core-toolbar') {
this.activePage = 4;
}
}
});
</script>
As a general rule, try to avoid using id at all in your template. That means your element is data-driven, and you can redesign your UI without touching your script.

Categories

Resources