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>
Related
I'm trying to achieve a navigation bar that has initial styling but at the end of a specific container, I'm wanting to update the styling of the navigation bar.
<template>
<div style="position:fixed" class="mynav" ref="desktop">
content..
</div>
</template>
mounted () {
window.document.body.onscroll = () => {
console.log(this.$refs.desktop.scrollHeight)
}
}
but the scrollHeight is always the same. How can I figure out where the position:fixed element is located at on window scroll?
try this :
<template>
<div class="container-body" #mousewheel="handelScroll">
<div style="position:fixed" class="mynav" ref="desktop">
content..
</div>
</div>
</template>
<script>
handelScroll(){
let scrollDiv = document.getElementsByClassName('mynav')
console.log(scrollDiv)
if(window.scrollY < 100){
console.log(window.scrollY , scrollDiv)
scrollDiv[0].classList.add('updateClass')
}
else{
scrollDiv[0].classList.remove('updateClass')
}
}
</script>
<style>
.updateClass{
display:none;
}
</style>
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
I want to create a Grid component that accepts the number of columns from the user, accepts data and renders all it's children into consecutive cells.
Something like this.
<Grid :cells="12" :columns="6">
<div>Child1 Cell1</div>
<div>Child2 Cell2</div>
<div>Child3 Cell3</div>
<div>Child4 Cell4</div>
<div>Child5 Cell5</div>
<div>Child6 Cell6</div>
</Grid>
In the Grid.vue component in the template, this is what I expect to do.
<div class="nugget-grid-item" v-for="cell of cells" :key="cell">
{cell}
</div>
This will render something like this on the UI.
The dashed border on each cell is due to the nugget-grid-item CSS class, but CSS is not relevant here, so let's ignore that.
What I am not able to figure out is how do I get this Grid component to display the following.
Isn't there something like this.children from React in Vue?
What you need are slots. See docs here. As you'll see slots allow a parent component to pass DOM elements into a child component. A basic look at them could go like this:
//ChildComponent.vue
<template>
<div>
<p>I'm the child component!</p>
<!-- Content from the parent gets rendered here. -->
<slot></slot>
</div>
</template>
And then you inject content into the slot tags like this:
//ParentComponent.vue
<template>
<div>
<child-component>
<p>I'm injected content from the parent!</p>
<p>I can still bind to data in the parent's scope, like this! {{myVariable}}</p>
</child-component>
</div>
</template>
Slots can get pretty complex and do a lot of things so are well worth looking into.
Further to your below comment, you can put a v-for in the grid. This outputs what you seem to be after. I've put an input in to accept the users number of columns as you said and it then renders that number of cells. You can of course use multiple slots and named slots and scoped slots but I'll leave it up to you how you expand on this.
//Grid.vue
<template>
<div class="cell">
<slot></slot>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.cell {
height: 40px;
width: 60px;
border: 1px solid gray;
}
</style>
and parent:
<template>
<div class="content">
<label>Enter number of columns</label>
<input v-model.number="col" type="number">
<Grid v-for="(n, i) in col" :key="i" >
<div>Child{{n}} Cell{{n}}</div>
</Grid>
</div>
</template>
<script>
import Grid from '#/components/admin/Grid'
export default {
layout: 'admin',
components: {
Grid
},
data: () => ({
col: 4
}),
}
</script>
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.
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.