Force vue 3 router to got to the same route twice - recognize it as a new event - vue.js

I use vue 3
I have a view that loads components inside it. Each time you click a text, router.push is called , and loads a component, with some params
click here
<h3 #click="handleClick('intro', 'abc')" >intro</h3>
to load component here
<router-view></router-view>
the click is handled as such
setup(){
const router = useRouter();
const handleClick = (part, term)=>{
router.push({name:part, params: {term}}).catch(err => {});
}
return{handleClick}
}
so router.push loads in <router-view> another smaller component (named intro), according to the router of the app, that is set like so
path: '/book',
name: 'book',
component: book,
children:[
{
path: 'intro/:term',
name: 'intro',
component: Intro
},
]
The component is loaded inside the view and the url is like /book/intro/abc
inside the intro component, to handle the change in the route and scroll down the abc id , I do
const route = useRoute();
let id = false;
let mounted = ref(false);
//grab the term from route, to set it as id and if component is mounted, scroll to id
watchEffect(()=>{
id = route.params.term;
let el = document.getElementById(id);
if (mounted && el) {
el.scrollIntoView({behavior: "smooth"});
id = false;
}
})
//check if mounted and if also id that came from route exists, scroll to id
onMounted(() => {
mounted = true;
let el = document.getElementById(id);
if (id && el) {
el.scrollIntoView({behavior: "smooth"});
id = false;
}
})
ISSUE
This works and is based on the route, to load the component and also set the id where it will scroll to.
But if I scroll to an id, then scroll randomly in the page and then click the same id to scroll, it will NOT scroll to that id again, because the id does not change, so route does not fire another event.
example : The url is /book/intro/abc. If I scroll randomly and then click the abc , url is the same, no event is fired, it will not scroll back to abc again.
How do I fix this? I want to avoid having hashtags or queries or questionmarks in my urls. Ideally I want "clean" urls like /book/part/term and I want to load that part indicated by the url, inside the view, not having all the parts loaded inside the view, as a super long text .
EDIT I also want to avoid reloads
Thanks

You can watch the whole route object and force the router change with the force option.
/* In the template */
<router-link :to="{ path: 'some-path', force: true }">link</router-link>
// In the script
const route = useRoute()
watch(() => route, () => {
console.log('route changed')
}, {
deep: true
})

Related

After adding a route to vue3 router. addRoute(), why is the page menu not updated?

console.log(router.getRoutes()); The number of arrays is increased by 1, and the menu is not updated
console.log(router.getRoutes()); //This array is 29,
//add route
router.addRoute('xitong2', {
path: '/projectbrowsing/duolianjixitong/xitong2',//
component: () => import('#/views/xitong/systemTabShow.vue'),
name: 'Xitong2',
meta: {
title: t('routers.xtyc'),
query: {
systemId: 'a02'
}
}
})
console.log(router.getRoutes()); //This array is 30,
Prompt
Note that adding routes does not trigger new navigation. That is, the added route will not be displayed unless a new navigation is triggered
Does triggering a new navigation refer to a page jump or something?

How do I set a fallback path/route with vueRouter if the navigation goBack ( < ) takes the user out of myb page?

I'm quite new with Vue, and vue-router. Right now I'm working on a page where we organize tennis matches, I have this component called goBack, it basically checks your browser history entries and take you back to the previous one, similar to the back-arrow in your browser. So I have this behavior which I don't like, and I don't know how to change it => if I set match, pass you the URL, if you enter and click on my goBack Comp it will take you out of my page. I want to avoid that with this logic, if your last browser history entry is not inside my page I want to redirect you to my home.
Here's the goBack component code:
setup(props, { attrs }) {
const router = useRouter()
const { t } = useI18n()
const goBack = (): void => {
if (attrs.onClick) return
if (router.options.history.state.back === null) {
router.replace('/')
} else {
router.back()
}
}
return {
t,
goBack
}
}
})
</script>
Thank you!

Load Vuex data in router before the component is rendered

I'm creating a Vue 2 website where the pages are linked in a linear workflow. Each page has its own route (e.g. /, /intro, /summary). I'm using Vuex to store the page number and total pages as well, so each page can show the text "Page X of Y" and use Next and Previous buttons to move forward and back in the workflow.
In my router, I use beforeEach to get the page # from the new route and set it on the store or redirect the user to the homepage. This commits a mutation because as far as I know, getting the route's path and looking up the page # of that route in an array are synchronous operations:
export default async ({ app }) => {
await app.router.beforeEach((to, from, next) => {
const pages = app.store.getters['pages/all']
const pageIndex = pages.indexOf(to.path)
if (pageIndex >= 0) {
app.store.commit('pages/set', pageIndex)
next()
} else {
next('/')
}
})
}
The Vuex store initializes the page index to 0 and uses an array to maintain the order of routes in the workflow:
export const state = () => ({
currentIndex: 0,
pages: [
'/',
'/intro',
'/summary'
]
})
export const mutations = {
set (state, newIndex) {
if (newIndex < 0) {
state.currentIndex = 0
} else if (newIndex >= state.pages.length) {
state.currentIndex = state.pages.length - 1
} else {
state.currentIndex = newIndex
}
}
}
However, when I navigate directly to /intro, the page shows "Page 1 of 3" for a moment before changing to "Page 2 of 3" as expected.
Since the mutation is a synchronous operation, I'm not sure why the content changes after the route is finalized and the page is drawn.
How can I adjust this solution so that the correct page number is shown when the page loads without showing an incorrect page # first?

how to change params value passed to axios route to change data react native?

I am building a kind of book app (Holy Quran )... user will go for a list of Surahs, each Surah contains around 5 - 50 pages. I managed navigating user from the list to first page of each Surahs.. and through getting an api request data for first page will be shown and this is the code in the showScreen
const [quran, setQuran] = useState([]);
const page = navigation.getParam('page');
const name = navigation.getParam('name');
let pageNumber = page;
useEffect(() => {
Quran();
}, []);
const Quran = async () => {
const response = await QuranApi.get(`/${pageNumber}/quran-uthmani`);
setQuran(response.data.data.ayahs);
}
so let's imagine that first page is page number 200, I am looking for some way so when user clicks go to page 201 or 199 (next or previous) and refetching the data so show for him requested page
I need some help here please and thanks in advance
Basically you need to add some sort of button or any element in your 'markup section' which will trigger next/previous action. For example:
// The following line makes react listen for changes in page state variable.
// If you use setPage() anywhere, react will auto update all the components
// where page variable is used. You don't need to manually do it
const [page, setPage] = useState(nav.getParam('page'))
// ....
// This function does exactly that
const handleClick = event => {
if(event.target.value === 'next-page') // If next button was pressed
setPage(page + 1) // We increment the page state variable by 1
else if(event.target.value === 'prev-page') // If prev button was pressed
setPage(page - 1) // We decrement the page state variable by 1
// By doing so, react will auto update every element which uses this variable
}
// .....
// We tell react, if [page] state variable changes by user clicking
// next or previous button, fetch data from the api using updated
// page number and using that, we update the [quran] variable using
// 'setQuran()' function
useEffect(async () => {
const response = await QuranApi.get(`/${page}/quran-uthmani`)
setQuran(response.data.data.ayahs)
}, [page] );
//......
// markup section
return(
//....
<Button onClick={handleClick} value="next-page">Next Page {page + 1}</Button>
<Button onClick={handleClick} value="prev-page">Prev Page {page - 1}</Button>
//....
)
Thank you dear #Sayed it finally works but I have to make some modifications with the same idea to be
const [page, setPage] = useState(navigation.getParam('page'))
const handleRightClick = () => {
setPage(parseInt(page) + 1)
};
const handleLeftClick = () => {
setPage(parseInt(page) - 1);
}
useEffect(() => {
return () => {
console.log("cleaned up");
};
}, []);
useEffect(() => {
Quran();
}, [page]);
<Button title = 'Next Page' onPress = {handleRightClick}/>
<Button title = 'Prev-page' onPress ={handleLeftClick} />
So it's working well in that case without an error
Try this small change...
const [page,setPage]=useState(nav.getParam('page'))
useEffect(() => {
Quran();
}, [page]);
by passing an empty array as a second parameter to the useEffect function, you are telling react to only execute the side effect once (at mount time).
However if that array contains a list of state variables to watch for. React will only re-run the side effect if one of the items in this array changes.
The above mentioned change in useEffect would make your useEffect sensitive to any change in the state variable (page) passed to the useEffect array. As you pass new pagenumbers in the url as a parameter, it would result in calling useEffect everytime as the page state variable is set.
Hope this helps!

How update a VUE component changing URL param in current page

In my vue SPA I have a simple router like this:
{path: '/page/:userId', name: 'user', component: user},
Which means an url like http://xxx.xxx/user/1 shows the component user having the content about user 1.
In case on the same page I have some link as
<vue-link :to="{name:'user', params={userId:3}}">
The router update only the URL but the content page (because it assumes the page is the same where I'm at)
My user content loads data using the url params in data and in watch too
data
userId: this.$route.params.userId || 1,
watch
watch: {
userId: function () {
return this.$route.params.userId || 1;
},
How to fix it without using router-view?
Thanks for any suggestion
If I correctly get your problem which is that you are not able to track your route change. You need to watch the route change, whenever your route changed on a same component it should do something.
watch: {
$route() {
this.updatePage(this.$route.params.userId)
}
},
methods: {
updatePage(param) {
// call api / do something
}
}