$vuetify.goTo('#foo') not working on another router page - vue.js

I try to smooth scroll using the function: goTo("#how") provided by Vuetify. It worked fine but when I go to a different router page it gives an error.
[Vue warn]: Error in v-on handler: "Error: Target element "#how" not found."
In my knowledge, it means that the target element does not exist.
I tried changing goTo("/#how"), goTo("/how") but it seems to be of no hope.
//App.vue where the header, footer of my app exist and the button that calls the function: goTo()
<v-btn #click="() => this.$vuetify.goTo('#how')">How it Works</v-btn>
//The section where the page should scroll when the button is clicked
<section id="how">
</section>
//the goTo scroll function provided by Vuetify
scrollBehavior: (to, from, savedPosition) => {
let scrollTo = 0
if (to.hash) {
scrollTo = to.hash
} else if (savedPosition) {
scrollTo = savedPosition.y
}
return goTo(scrollTo)
}
I expect it when on another route page and the button is clicked, it should scroll smoothly to the section.

So, I have found a solution to my problem. It may not be the cleanest way but it works.
My solution is to put a conditional statement for the buttons.
//First check if the current route is on landing page (or wherever your #foo is) then set the click function for it.
<v-btn v-if='this.$route.path == "/"' color="white" #click="() => this.$vuetify.goTo('#foo')" flat>How it Works</v-btn>
//If route.path is not at "/" then we call the router push to redirect first to Landing and then scroll.
<v-btn v-else color="white" #click="() => this.$router.push('/#foo')" flat>How it Works</v-btn>

Related

Vuetify bottom navigation not removing active state on route change after hard refresh

In my app I have a bottom navigation component set up as such:
<v-bottom-navigation
v-else
background-color="overlay"
grow
app
color="primary"
>
<v-btn
v-for="(route, key) in routes"
ref="link"
:key="'route' + key"
:to="route.to"
min-width="48"
class="px-0"
>
<span v-if="$vuetify.breakpoint.smAndUp">{{ route.name }}</span>
<v-icon>{{ route.icon }}</v-icon>
</v-btn>
</v-bottom-navigation>
This works well, I can use it to navigate around my app as intended. When clicking one of the buttons on the bottom navigation, the button state updates as it should to show that it is active (primary color).
My routes are defined as follows:
routes: [
{ icon: mdiViewDashboard, name: 'Dashboard', to: '/dashboard' },
{ icon: mdiCart, name: 'Orders', to: '/orders' },
{ icon: mdiDolly, name: 'Receiving', to: '/receiving' },
{ icon: mdiClipboardText, name: 'Tasks', to: '/tasks' },
{ icon: mdiTruck, name: 'Deliveries', to: '/deliveries' },
],
I have an additional route /settings which is not part of this main navigation, but defined on the header bar of my application as such:
<v-btn
aria-label="Settings"
icon
to="/settings"
>
<v-icon>{{ mdiCog }}</v-icon>
</v-btn>
Since the settings button/router link is not part of the bottom navigation, when I click on the settings button, it disables the active state on the buttons in the bottom navigation, as it should since it is not part of the bottom navigation.
Here is where the odd behavior occurs:
If I am in one of the routes defined on the bottom navigation, and hard refresh the page I refresh to the proper location. From here, if I click the settings button, the router displays the settings as it should, but the active state on the bottom navigation of the stale state still shows. This only occurs on a hard refresh, if I select a bottom navigation route, and then go to settings, it removes the active state from the bottom navigation button.
In my research I thought it may be an issue with the exact property for the router links, but it seems to make no different.
Additionally, I set a breakpoint to display the bottom navigation on small and below, if I stretch the window to hide the bottom navigation, then shrink it to re-show, when the component is shown again, it has the proper state.
Reloading the page isn't the only way to reproduce the bug. The buttons in the navigation group appear to be toggleable both by VItemGroup logic and VBtn's routable mixin. You can replicate the problem by clicking any nav button two times and routing to /settings after that. If you inspect the element in that state, the active class v-btn--active is duplicated 3 times. Routing to another page removes only the exact matches of v-btn--active v-btn--active, leaving the third one on the element.
Clearly, this is not an intended behavior.
But the workaround is quite simple. Setting every button's active-class prop to anything but 'v-btn--active' will do the trick.
So, for example:
<v-btn
v-for="(route, key) in routes"
ref="link"
:key="'route' + key"
:to="route.to"
min-width="48"
class="px-0"
active-class=""
>
<span v-if="$vuetify.breakpoint.smAndUp">{{ route.name }} </span>
<v-icon>{{ route.icon }}</v-icon>
</v-btn>

Ionic 4 navigate to another page inside modal

I have a modal and everytime when I have to navigate to other pages I have to close the modal and then go to that page. But I want to navigate to a particular page without dismissing the modal. Means opening page inside modal without really dismissing it and passing back data from that page to modal.
Is it possible to do it?
Thank you in advance
My code :
.ts to create modal
async address_modal(){
// console.log("clicked")
console.log(this.user_id)
const modal = await this.modalController.create({
component: AddressModalPage,
cssClass : 'address-modal',
componentProps : {
user_id : this.user_id
}
});
return await modal.present();
}
html to open modal from button
<ion-button(click)="address_modal()"> </ion-button>
modal.html // open another page
<ion-button routerLink="menu/items/address/add-address" style="text-transform:none" color= "primary" fill ="clear" (click) = "add_address()" >
<ion-icon name="add" ></ion-icon> Add new address
</ion-button>
I think the problem here is the routerLink, but i'm not really sure about this.
When i want to navigate from a modal to another page i use this.
export class test implements OnInit{
constructor(private router: Router) { }
moveNext(){
this.router.navigate([page]);
}
}
You just need to import this: import { Router } from '#angular/router';. And then put it on a button like this:
<ion-button expand="block" (click)="moveNext()">Go to next page </ion-button>

How can I get CKEditor 5 "Link" dialog box to pin to custom DOM element instead of 'document.body'

I'm building a Vue.js web application. I'm using CKEditor in a form that is placed inside a modal window. By design, the user's focus is "trapped" in the modal. In CKEditor, when user clicks the "Link" icon in toolbar, the editor opens a dialog box and attaches the new DOM element to 'document.body'. With respect to the DOM, the "Link" dialog is now outside of trapped focus. The user cannot click or tab his way to the "Link" dialog input.
I dug into the ckeditor5-ui source and found relevant code in balloonpanelview.js. I've unsuccessfully tried to configure CKEditor based on https://ckeditor.com/docs/ckeditor5/latest/api/module_utils_dom_position-Options.html
In my Vue.js component, I have:
import ClassicEditor from '#ckeditor/ckeditor5-build-classic';
...
data: () => ({
editor: ClassicEditor,
editorConfig: {
toolbar: ['bold', 'italic', 'bulletedList', 'numberedList', 'link'],
},
...
})
...
I want the CKEditor "Link" dialog DOM element to be attached to a DOM element id that I specify.
In Vuetify dialog component is required to disable retain-focus
<v-dialog :retain-focus="false" />
There may be much time since you opened the issue. However... This issue was happening to me too. This is happening because Bootstrap modal trap the focus in the active modal. If you're using bootstrap-vue, do this.
In your <b-modal> add the prop no-enforce-focus.
no-enforce-focus is reactive. To properly apply this workaround you can use this prop with a variable, that detects when your CKeditor have focus. If have focus, disable the enforce focus. If doesn't have, restore it. You can apply it by the following way:
<template>
<b-modal
...
:no-enforce-focus="editorFocus">
<ckeditor
...
#focus="toggleEditorFocus(true)"
#blur="toggleEditorFocus(false)"
/>
</b-modal>
</template>
<script>
export default {
...
data () {
return {
editorFocus: false
}
},
methods: {
toggleEditorFocus (val = !this.editorFocus) {
setTimeout(() => {
this.editorFocus = val
}, 10)
}
}
}
</script>
I know the setTimeout is a tricky method, but at least is working now for me.

Navigate with nuxt-link to anchor/hash on different page causing problems

I am using nuxt-links in my website navigation, most of them point to hashed elements/anchors in the home page like:
<nuxt-link
v-else
class="text-link"
:to="localePath('index') + `#${item.hash}`"
>
and it does its job if currently on the home page but when I navigate to a different site, eg. /about and I click on a navbar nuxt-link (so I want to navigate from /about to /#hash or /any-other-site#hash) I got a nuxt error displayed to check the console where it reads "Cannot read property 'offsetTop' of null"
My router configuration in nuxt.config (without it I wouldn't be even able to scroll to an anchored element being in the same site as the element!):
router: {
scrollBehavior(to) {
if (to.hash) {
return window.scrollTo({ top: document.querySelector(to.hash).offsetTop + window.innerHeight, behavior: 'smooth' });
}
return window.scrollTo({ top: 0, behavior: 'smooth' });
}
},
You have not defined the hash in your nuxt-link. Use:
<nuxt-link
v-else
class="text-link"
:to="{ path: localePath('index'), hash:`#${item.hash}` }"
>

How to "re-activate" a link once the user scrolls away from an anchor section?

I'm using Vue.js 2.3.3 with vue-router 2.5.3. I created a Navbar component that has bookmarks (or links) pointing to specific sections on the landing page, like so:
<router-link to="/#our-services" class="nav-item item is-tab">
Our Services <!-- Jumps to #our-services on the home page -->
</router-link>
I defined my router in the following way:
export default new VueRouter({
routes, // routes are defined in a var above...
mode: 'history',
scrollBehavior(to, from, savedPosition) {
if (to.hash) {
return { selector: to.hash }
} else {
return { x: 0, y: 0 }
}
},
linkActiveClass: 'is-active'
})
Now, this does seem work; if I click on "Our Services" link in the navbar, it jumps to #our-services. However:
If I scroll away from #our-services div element, and click on "Our Services" link again, it doesn't bring me back to the div; clicking on the link does not produce anything;
Moreover, the <a> element of the router-link retains the is-active class even though you scrolled away from the section; it would be nice to keep track of where you are on the page and adjust the is-active class on the link appropriately.
Any suggestions on how to solve these two problems? Should I listen to the scroll event in the second case? Thanks!
Whatever your scrolling object is (likely window), you should add an event listener to handle scroll events:
window.addEventListener('scroll', scrollHandler, false);
Your scrollhandler function should check whether there is a hash on the current window location, and if so, check whether the associated element is out of range, and if so, clear the hash.
I can't use the real location hash or window in a snippet, but this is kind of what you would want to do.
let hash = '#second';
const scrollingEl = document.querySelector('.scrollingArea');
function handleScrollEvent() {
if (hash) {
const winY = scrollingEl.scrollTop;
const hashElY = document.querySelector(hash).getBoundingClientRect().top;
if (hashElY < 0 || hashElY > winY + scrollingEl.height) {
hash = '';
}
console.log(winY, hashElY);
}
}
scrollingEl.addEventListener('scroll', handleScrollEvent, false);
.scrollingArea {
height: 400px;
overflow-y: scroll;
}
.scrollingArea>div {
height: 250px;
}
<div class="scrollingArea">
<div id="first">First</div>
<div id="second">Second</div>
<div id="third">Third</div>
<div id="fourth">Fourth</div>
</div>