I have multiple scrollbars to my page, but can't make them working properly :
<div class="dates-container" v-for="id in ids">
<overlay-scrollbars
:ref="`datesHeader`+id"
:options="datesScrollOptions"
:key="id"
>
</div>
......
resetScroller() {
this.$nextTick(() => {
if (this.$refs[`datesHeader${this.currentRoom}`][0]) {
const inst = this.$refs[`datesHeader${this.currentRoom}`][0].osInstance();
if (inst == null) return;
const state = inst.getState();
if (state.hasOverflow.x) {
inst.scroll({ x: 0 });
}
this.updateScrollButtons();
}
});
},
Like that is working fine; The problem is when I tried to identify which scrollbar was moved and how I can update this.currentRoom when scrollbar is moved;
Firsty u have wrong :ref value - should be :ref="`datesHeader-${id}`"
then on onMounted you can add event listners to $refs
onMounted() {
this.$refs['datesHeader-0'].addEventLister('scroll', watchFunc)
}
DOCS:
https://developer.mozilla.org/pl/docs/Web/API/EventTarget/addEventListener
remember to remove event listeners in onBeforeUnmount
also, IntersectionObserver could be good for tracking scroll
DOCS: https://developer.mozilla.org/enUS/docs/Web/API/Intersection_Observer_API
I have a woking accessible responsive navigation which for DEMO perpuses I have to make it reusable so I can show different sort of senarios. However tho, the click burger menu is not working.
This header with responsive navigation should work indipenently multiple times.
On click and matchMedia
typial responsive nav behavious with an extra touch of matchMedia in case user moves the window.
open navigation on click and remove navigation if > 900
navigation remove Attribute hidden on desktop and on click.
All of this should work multiple times.
if (navBlocks.length > 0){
Array.prototype.forEach.call(navBlocks, function(el) {
the forEach function shoud do the work right? how come is not really working?
DEMO HERE
const navBlocks = document.querySelectorAll('.nav-container');
const nav = document.querySelector('.sliding-nav');
const menu = document.querySelector(".sliding-nav ul");
const toggleMenu = document.querySelector(".nav-container .nav-cta");
const mediaQuery = window.matchMedia('(min-width: 900px)');
let isMenuOpen = false;
if (navBlocks.length > 0) {
Array.prototype.forEach.call(navBlocks, function(el) {
el.addEventListener('click', e => {
e.preventDefault();
isMenuOpen = !isMenuOpen;
toggleMenu.setAttribute('aria-expanded', String(isMenuOpen));
menu.hidden = !isMenuOpen;
if (isMenuOpen) {
nav.classList.add('is-open');
document.body.classList.add("is-no-scroll", "is-fixed");
//console.log(isMenuOpen);
} else {
nav.classList.remove('is-open');
document.body.classList.remove("is-no-scroll", "is-fixed");
//console.log(!isMenuOpen);
}
});
function handleTabletChange(e) {
// Check if the media query is true
if (e.matches) {
toggleMenu.setAttribute("aria-expanded", false);
menu.removeAttribute("hidden");
nav.classList.remove('is-open');
document.body.classList.remove("is-no-scroll", "is-fixed");
} else {
toggleMenu.setAttribute("aria-expanded", false);
//nav.removeAttribute("aria-expanded");
}
}
// Register event listener
mediaQuery.addListener(handleTabletChange);
// Initial check
handleTabletChange(mediaQuery);
});
}
I think you should do something like this,
add event listener on burger menu icon to toggle an active class in nav bar and you should write css for that active class that if nav contains "active" class it should be set to display or else it should display none!
This question already has answers here:
Getting the ID of the element that fired an event
(24 answers)
Closed 10 months ago.
<tooltip message="Click" content="preview"></tooltip>
<tooltip message="Tooltip 1" class="repeat-tooltip" content="Click tooltip 1 preview"></tooltip>
<tooltip trigger="hover" class="repeat-tooltip" message="Hover Tooltip" content="Hover tooltip preview"></tooltip>
New and trying to create a custom tooltip tag and only one tooltip will be active at a time.
<tooltip>
<p class="tooltip-content" control="tooltip">{ message } ref="target"</p>
<div class="tooltip-wrapper" show={show_message} ref="content">
//inner html
</div>
</tooltip>
Trying to use show toggling show_message value to display and hide the tooltips. But show_message is within the context of that particular elements click event. Onclick of a particular tooltip, how can I access other custom tag's context to hide the value of that particular element if that tooltip already open?
this.root.addEventListener('click', (e) => that.toggle_message(e));
this.toggle_message = function(e) {
//here close all other tooltips before opening this one. How can I access the refs of all the open tooltip?
this.show_message = !this.show_message;
this.update();
};
From the specs of Riot.js I could not find anything that will allow you to keep track of all tags of same type so solution that I can think of for this particular scenario is to store collection of tooltips under windows and show/hide them on click of each individual tooltip.
As I do not have all component that you posted, I created bare minimum working example over here.
My demo component look like:
<tooltip>
<p>{ content }</p>
<span riot-style="display: { show_message ? 'inline-block' : 'none' }; background: black; color: white; padding:3px;"> { message } </span>
const self = this;
this.content = opts.content || '';
this.message = opts.message || '';
this.root.addEventListener('click', (e) => self.showTooltip(e));
this.toggle_message = function(show) {
self.show_message = show;
self.update();
};
this.showTooltip = function(e){
const bShow = !self.show_message;
for(var i=0; i<window.tooltips.length; i++){
window.tooltips[i].toggle_message(false);
}
self.toggle_message(bShow);
};
<script>
this.on('mount', function(){
if(!window.tooltips)
window.tooltips = [];
window.tooltips.push(this);
});
</script>
</tooltip>
On mount event it adds it's self to window.tooltips array collection and later when one of the components is clicked, event handler iterates through all registered components and hides them before showing current component.
Update - I found a better solution here using riot events. Add the events to windows and listen to that event on document body click and other trigger elements click, so that you will get the context of all tooltips and close it.
I have a Vue.js component with several elements in it. I want to automatically scroll to the bottom of that element when a method in the component is called.
Basically, do the same as this. However, I haven't found a way to get the element within my component and modify scrollTop
I'm currently using Vue.js 2.0.8.
2022 easy, readable, smooth scrolling ability, & won't hurt your brain... use el.scrollIntoView()
scrollIntoView() has options you can pass it like scrollIntoView({behavior: 'smooth'}) to get smooth scrolling out of the box and does not require any external libraries.
Here is a fiddle.
methods: {
scrollToElement() {
const el = this.$refs.scrollToMe;
if (el) {
// Use el.scrollIntoView() to instantly scroll to the element
el.scrollIntoView({behavior: 'smooth'});
}
}
}
Then if you wanted to scroll to this element on page load you could call this method like this:
mounted() {
this.scrollToElement();
}
Else if you wanted to scroll to it on a button click or some other action you could call it the same way:
<button #click="scrollToElement">scroll to me</button>
The scroll works all the way down to IE 8. The smooth scroll effect does not work out of the box in IE or Safari. If needed there is a polyfill available for this here as #mostafaznv mentioned in the comments.
As I understand, the desired effect you want is to scroll to the end of a list (or scrollable div) when something happens (e.g.: an item is added to the list). If so, you can scroll to the end of a container element (or even the page it self) using only pure JavaScript and the VueJS selectors.
var container = this.$el.querySelector("#container");
container.scrollTop = container.scrollHeight;
I've provided a working example in this fiddle.
Every time a item is added to the list, the list is scrolled to the end to show the new item.
I tried the accepted solution and it didn't work for me. I use the browser debugger and found out the actual height that should be used is the clientHeight BUT you have to put this into the updated() hook for the whole solution to work.
data(){
return {
conversation: [
{
}
]
},
mounted(){
EventBus.$on('msg-ctr--push-msg-in-conversation', textMsg => {
this.conversation.push(textMsg)
// Didn't work doing scroll here
})
},
updated(){ <=== PUT IT HERE !!
var elem = this.$el
elem.scrollTop = elem.clientHeight;
},
Use the ref attribute on the DOM element for reference
<div class="content scrollable" ref="msgContainer">
<!-- content -->
</div>
You need to setup a WATCH
data() {
return {
count: 5
};
},
watch: {
count: function() {
this.$nextTick(function() {
var container = this.$refs.msgContainer;
container.scrollTop = container.scrollHeight + 120;
});
}
}
Ensure you're using proper CSS
.scrollable {
overflow: hidden;
overflow-y: scroll;
height: calc(100vh - 20px);
}
Here is a simple example using ref to scroll to the bottom of a div.
/*
Defined somewhere:
var vueContent = new Vue({
el: '#vue-content',
...
*/
var messageDisplay = vueContent.$refs.messageDisplay;
messageDisplay.scrollTop = messageDisplay.scrollHeight;
<div id='vue-content'>
<div ref='messageDisplay' id='messages'>
<div v-for="message in messages">
{{ message }}
</div>
</div>
</div>
Notice that by putting ref='messageDisplay' in the HTML, you have access to the element through vueContent.$refs.messageDisplay
If you need to support IE11 and (old) Edge, you can use:
scrollToBottom() {
let element = document.getElementById("yourID");
element.scrollIntoView(false);
}
If you don't need to support IE11, the following will work (clearer code):
scrollToBottom() {
let element = document.getElementById("yourID");
element.scrollIntoView({behavior: "smooth", block: "end"});
}
Try vue-chat-scroll:
Install via npm: npm install --save vue-chat-scroll
Import:
import Vue from 'vue'
import VueChatScroll from 'vue-chat-scroll'
Vue.use(VueChatScroll)
in app.js after window.Vue = require('vue').default;
then use it with :
<ul class="messages" v-chat-scroll>
// your message/chat code...
</ul>
For those that haven't found a working solution above, I believe I have a working one. My specific use case was that I wanted to scroll to the bottom of a specific div - in my case a chatbox - whenever a new message was added to the array.
const container = this.$el.querySelector('#messagesCardContent');
this.$nextTick(() => {
// DOM updated
container.scrollTop = container.scrollHeight;
});
I have to use nextTick as we need to wait for the dom to update from the data change before doing the scroll!
I just put the above code in a watcher for the messages array, like so:
messages: {
handler() {
// this scrolls the messages to the bottom on loading data
const container = this.$el.querySelector('#messagesCard');
this.$nextTick(() => {
// DOM updated
container.scrollTop = container.scrollHeight;
});
},
deep: true,
},
The solution did not work for me but the following code works for me. I am working on dynamic items with class of message-box.
scrollToEnd() {
setTimeout(() => {
this.$el
.getElementsByClassName("message-box")
[
this.$el.getElementsByClassName("message-box").length -
1
].scrollIntoView();
}, 50);
}
Remember to put the method in mounted() not created() and add class message-box to the dynamic item. setTimeout() is essential for this to work. You can refer to https://forum.vuejs.org/t/getelementsbyclassname-and-htmlcollection-within-a-watcher/26478 for more information about this.
This is what worked for me
this.$nextTick(() => {
let scrollHeight = this.$refs.messages.scrollHeight
window.scrollTo(0, scrollHeight)
})
In the related question you posted, we already have a way to achieve that in plain javascript, so we only need to get the js reference to the dom node we want to scroll.
The ref attribute can be used to declare reference to html elements to make them available in vue's component methods.
Or, if the method in the component is a handler for some UI event, and the target is related to the div you want to scroll in space, you can simply pass in the event object along with your wanted arguments, and do the scroll like scroll(event.target.nextSibling).
I had the same need in my app (with complex nested components structure) and I unfortunately did not succeed to make it work.
Finally I used vue-scrollto that works fine !
My solutions without modules:
Template
<div class="scrollable-content" ref="conversations" />
Script
scrollToBottom() {
const container = this.$refs.conversations;
container.scrollTop = container.scrollHeight;
},
scrollToBottom() {
this.$nextTick(function () {
let BoxEl = document.querySelector('#Box');
if(BoxEl)
BoxEl.scrollTop = BoxEl.scrollHeight;
});
}
Agree with Lurein Perera
Just want to add extra info
watch: {
arrayName: {
handler() {
const container = this.$el.querySelector("#idName");
this.$nextTick(() => {
container.scrollTop = container.scrollHeight;
});
},
deep: true,
},
},
Where as:
arrayName = Name of array
idName = The id attribute has to be added to the div where you want the scrollbar to auto-scroll down when arrayName length increases.
scrollToElement() {
const element = this.$refs.abc; // here abc is the ref of the element
if (element) {
el.scrollIntoView({behavior: 'smooth'});
}
}
}
here you need to use ref for the particular div or element which you want make visible on scroll.
if you have a table and you want to locate the last row of the table then you have to use -
element.lastElementChild.scrollIntoView({behaviour:'smooth'})
Here not that if you ware asynchronously adding the element to the table then you have to take care of it. you can test it using setTimeout, if that is making any difference.
e.g.
const element = this.$refs.abc;
if (element) {
setTimeout(() => {
element.lastElementChild.scrollIntoView({behaviour:'smooth'})
}, 1000);
}
}
replace set timeout with your own async logic.
Using Composition API and TypeScript
I set the parameter scrollTop equal to scrollHeightfrom the HTMLDivElment API.
<template>
<div id="container" ref="comments">
Content ...
</div>
</template>
<script lang="ts">
import { defineComponent, ref, Ref, watchEffect } from 'vue'
export default defineComponent({
setup() {
const comments: Ref<null | HTMLDivElement> = ref(null)
watchEffect(() => {
if(comments.value) {
comments.value.scrollTop = comments.value.scrollHeight
}
})
return {
comments
}
}
})
</script>
I have a kendo UI treewiew, which represents some directory structure and context menu:
#(Html.Kendo().ContextMenu()
.Name("menu")
.Target("#treeview")
.Orientation(ContextMenuOrientation.Horizontal)
.Animation(animation => animation.Open(open =>
{
open.Fade(FadeDirection.In);
open.Duration(500);
}))
.Items(items =>
{
items.Add()
.Text("Test");
})
//.Events(e=>e.Open("contextOpen"))
)
<div class="treeview-back">
#(Html.Kendo().TreeView()
.Name("treeview")
.TemplateId("treeview-template")
.Checkboxes(checkboxes => checkboxes
.Name("checkedFiles")
.CheckChildren(true)
)
.Events(events => events
.Check("onCheck")
)
.DataTextField("Name")
.DataSource(dataSource => dataSource
.Model(m => m.Id("Path").HasChildren("HasChildren"))
.Read("ReadDirectory", "Download"))
)
I need to show context menu only for elements that represent folders. But I can't find the way to show kendo context menu by condition. I added right click capturing method, which looks like this:
$("#treeview").on('mousedown', '.k-item', function (event) {
var treeView = $('#treeview').data('kendoTreeView');
var dataSource = treeView.dataSource;
var itemUId = $(this).attr("data-uid");
var node = dataSource.getByUid(itemUId);
if (event.which === 3 && node.hasChildren) {
event.stopPropagation(); // to avoid propagation of this event to the root of the treeview
$('#treeview').data('kendoTreeView').select(this);
...//here I should prevent context menu from showing somehow
}
});
but I can't find the way to cancel context menu showing. I also tried to add open event to context menu, but I can't get selected item there.
Thanks in advance.
To show menu due to the condition use filter property of ContextMenu object:
#(Html.Kendo().ContextMenu()
.Name("menu")
.Filter(".menu-on")
)
It only shows menu for items that has class menu-on.
Secondly you have to add this class to all your folders. You should find by javascript all <span class="k-in"> elements in your tree and add menu-on class to all elements associated with folders.