I have configured routes as follows in a sub module loaded dynamically.
I don't think the dynamic loading is causing the problem, but it may - so I have included it for reference.
dynamic load
children: [
{
path: "dashboard",
loadChildren: () => new Promise(resolve => {
(require as any).ensure([],
require => {
resolve(require("./dashboard/dashboard.module").DashboardModule);
},
"dashboard");
})
},
dashboard-routing-module
const routes: Routes = [
{
path: "",
component: ClearingDashboardComponent,
data: {
title: "Dashboard"
}
},
{
path: "logs",
component: LogDisplayComponent,
data: {
title: "Logs"
}
}
];
the landing HTML looks as follows
When navigating to the LogDisplayComponent with
const ne: NavigationExtras = {
queryParams: { ... }
};
this.router.navigate(["dashboard/logs"], ne);
A new component is being added above the HTML.
Surely each component should replace the inner HTML?
The LogDisplayComponent is above the ClearingDashboardComponent,
As I click, a new component is added each time I navigate either way?
How do I fix the route to replace the component rather than add a new one?
I am using angular 4.4.4...
Try updating your version to 5+. This issue has already been addressed by the Angular team. For more information, check these links:
https://github.com/angular/angular/issues/17261
https://github.com/angular/angular/issues/13725
Related
This is my code within in router.js file
{
name: "Admin",
path: "/admin/",
component: () => import("#/views/admin/Index"),
children: [
// Dashboard
{
name: "Dashboard",
path: "dash",
component: () => import("#/views/admin/Dash"),
},
{
name: "Campaign Management",
path: "campaign",
component: () =>
import("#/views/CampaignManagementNew/CampaignManagment"),
},
]
}
I set a variable 'status' in the localStorage.
I want to route only, if 'status' is true (localStorage item).
Otherwise, I not need to routing to child components.
How I use if conditions to routing?
You want to implement a pretty common pattern for 'protecting' routes behind a flag. In order to accomplish this, you should add a meta property to the routes you want to 'protect' behind a secondary check (the localStore value). Then you will need to create a router guard that checks the meta flag and routes the user based on those conditions.
You can see an example of it here: https://router.vuejs.org/guide/advanced/meta.html#route-meta-fields
In your case you would want to replace the auth.loggedIn() with your function that can check the localStorage value. So something like this:
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresLocalStorageValue)) {
if (!checkLocalStorageValue()) {
next({ path: '/not-authorized-page-missing-local-store'})
} else {
next()
}
} else {
next() // make sure to always call next()!
}
})
I'm trying to make an Electron app with Vanilla, Javascript, CSS for the front end and I've read most Q&A's online that SPA is the way to go to have multiple pages in the app.
I have some ideas to implement it but don't really know if it's correct:
Create buttons that would hide/show some sections of the HTML. (Not entirely sure if this is SPA)
Use the router implementation in this video: https://www.youtube.com/watch?v=6BozpmSjk-Y
Here's a snippet of that implementation:
const router = async () => {
const routes = [
{ path: "/", view: Dashboard },
{ path: "/posts", view: Posts },
{ path: "/posts/:id", view: PostView },
{ path: "/settings", view: Settings }
];
// Test each route for potential match
const potentialMatches = routes.map(route => {
return {
route: route,
result: location.pathname.match(pathToRegex(route.path))
};
});
let match = potentialMatches.find(potentialMatch => potentialMatch.result !== null);
if (!match) {
match = {
route: routes[0],
result: [location.pathname]
};
}
const view = new match.route.view(getParams(match));
document.querySelector("#app").innerHTML = await view.getHtml();};
Although the only problem is when I type location.pathname in the console, Electron gives out the file path of the html and not the route exactly.
I'd appreciate if someone would share an example code or app the has been built with the same tech stack I'm using.
I need to set up global head in Nuxt for my app, which some subpages will overwrite. Those global head needs to contain translated data.
I created seoHead.js file with code:
import Vue from "vue";
export const $t = (sign) => Vue.prototype.$nuxt.$options.i18n.t(sign);
export default {
title: $t("seoGlobal.title"),
meta: [
{ charset: "utf-8" },
{ name: "viewport", content: "width=device-width, initial-scale=1" },
{
hid: "description",
name: "description",
content: $t("seoGlobal.description"),
},
{
hid: "ogSiteName",
name: "og:site_name",
content: "Test Page",
},
{
hid: "ogTitle",
name: "og:title",
content: $t("seoGlobal.ogTitle"),
},
(...)
],
};
I import and use this data in my index.vue and other pages like this:
import seoHead from "~/constants/seoHead";
export default {
head() {
const metaI18n = this.$nuxtI18nSeo();
const currentPath = process.env.LP_URL + this.$router.currentRoute.fullPath;
return {
...seoHead,
meta: [
{
hid: "ogLocale",
name: "og:locale",
content: metaI18n.meta[0].content,
},
{
hid: "ogLocaleAlternate",
name: "og:locale:alternate",
content: metaI18n.meta[1].content,
},
{
hid: "ogUrl",
name: "og:url",
content: currentPath,
},
],
};
},
(...)
Unfortunately, I am facing Cannot read property '$options' of undefined error. It's strange for me, because I already used export const $t = (sign) => Vue.prototype.$nuxt.$options.i18n.t(sign); code in another js file. Anyone know why this error appears? You know the best way to translate global head options?
As discussed in the comments, there seems to be a timing issue with the Nuxt lifecycle and your component: at the time your component seoHead.js is imported, Nuxt has not yet injected its $nuxt object into Vue. So an easy workaround would be to delay the execution of your $t function (which accesses $nuxt):
Change your component to export a function which returns the object, instead of directly exporting the object:
export default function() {
return {
title: $t("seoGlobal.title"),
// ...
}
}
In index.vue, change your head function to call seoHead when spreading it:
return {
...seoHead(),
// ...
This way, the code which accesses $nuxt will be executed later -- not when seoHead is imported, but only when the head function is executed. At this time, the Nuxt lifecycle hopefully has finished its startup work and the required object is in place.
As I said, this is merely a workaround; if you would be calling head immediately in index.vue, the same error would appear. So unless you find out a proper way to integrate into the Nuxt lifecycle, I suggest to also put a safeguard into your translation function:
const $t = (sign) => Vue.prototype.$nuxt
? Vue.prototype.$nuxt.$options.i18n.t(sign)
: sign
This will return the i18n key if the required infrastructure is not yet in place. Not great, but better than an exception ;)
Alternatively you might be able to directly import your i18n functionality, without going through Nuxt at all; this way you wouldn't have any dependency on the infrastructure at all -- much better.
I think what you basically need here is a mixin.
export default {
title: $t("seoGlobal.title"),
meta: this.computedMeta,
computed:{
computedMeta(){
return [....] // this contains the array of objects in meta
}
}
methods:{
yourMethod(sign){
return this.$nuxt.$options.i18n.t(sign);
}
}
};
then just import it as a mixin in whatever file you need.
In my Vue.js project, I want to display my 404 page, if a route parameter is invalid. For now, I'm using the following code for that:
this.$router.replace({ path: '/404' });
Is there a way to do that without modifying the URL? I want the user to still be able to copy the browser's original URL line. Is there some kind of a silent: true parameter?
With vue-router, the URL is the source of truth. If the URL changes, so does the rendering. You can't "pause" the router. (This is a flaw in vue-router that has been bugging me for ages, but I digress.)
You just have to display the 404 page without modifying the route. Have some display404 data property in your root component that you can set to display the 404 page manually in the template instead of the <router-view>, e.g:
<div>
<my-404-page v-if="display404"/>
<router-view v-else/>
</div>
To display the 404 page from any component:
this.$root.display404 = true
Of course this is just a basic example to demonstrate what I mean, you might want to use Vuex to share the state, or use an event bus, or you can display the 404 page in some other way that works for you, etc.
This was fixed in Vue Router 4 which you can see on the second example in the docs.
Build your NotFound route like this:
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: NotFound
},
Then you can use a beforeEnter navigation guard on your dynamic Vue like so:
// In your router/index.js file...
{
path: 'users/:id',
name: 'User Detail',
component: UserDetail,
beforeEnter(to, from) {
// See if that query exists in your data...
const exists = data.users.find(
user => user.id === parseInt(to.params.id)
)
if (!exists) {
// THE IMPORTANT PART
// Return your not found view...
return {
name: 'NotFound',
// Match the path of your current page and keep the same url...
params: { pathMatch: to.path.split('/').slice(1) },
// ...and the same query and hash.
query: to.query,
hash: to.hash,
}
}
}
}
Haven't tested this in a Component yet, but I'd assume it'd be the same logic in the beforeRouteEnter navigation guard.
Not 100% sure what you are asking, but is either of these any help?
A catch all route:
From Vue.js docs "Catch all route"
Or if you are managing a response form a call (method/fetch/ etc): Use a combination of try/catch and a "loading" data value to change the display or what component is loaded.
Based on Decade Moon's solution, I did the following:
main.js
import Error404 from './views/error/404.vue'
Vue.component('error-404', Error404)
404.vue
<template>
<div>
<h1>Page not found</h1>
<p>Whatever...</p>
</div>
</template>
<script>
export default {
name: 'Page not found'
}
</script>
router --> index.js
const PageNotFound = () => import('#/views/error/404')
function configRoutes() {
return [
{
path: '/',
name: 'Home',
component: TheContainer,
children: [
// ...
{
path: '404',
name: 'Page not found',
component: PageNotFound,
alias: '*'
}
]
}
]
}
My Page which should display the 404 error
<template>
<div class="animated fadeIn" v-if="clientSettings">
...
</div>
<error-404 v-else></error-404>
</template>
<script>
export default {
name: 'Test',
data() {
return {
clientSettings: null
};
},
async created() {
this.setClientConfig();
},
watch: {
'$route.params.id': function (id) { this.setClientConfig(id);}
},
methods: {
setClientConfig(id) {
if (!id) {
id = this.$route.params.id;
// Redirect to the first valid list, if no parameter is proviced
if (!id) {
this.$router.push({ name: 'Test', params: { id: this.$root.clientConfiguration[0].name } });
return;
}
}
// Set client settings
this.clientSettings = this.$root.clientConfiguration.find(cc => cc.name === id);
// This will return null, if no entry was found, therefore the template will jump into the v-else
}
}
}
</script>
I am working on a project and using Vue.js for the frontend. I have following code in the main.js file.
new Vue({ // eslint-disable-line no-new
//el: '#app',
router,
data () {
return {
friends: []
}
},
methods: {
getFriends: function () {
return this.friends;
}
},
created: function () {
this.$http.get('/user/' + this.getUserIDCookie('userID') +
'/friends').then(function (response) {
this.friends = response.data;
});
},
components: {
'nav-bar': require('./components/Navigation.vue')
},
template: `
<div id="app">
<nav-bar></nav-bar>
<router-view class="router-view"></router-view>
</div>`
}).$mount('#app');
In one of the pages(for ex. when the page is redirected to localhost/#/user/1/details, I am retrieving the friends' list from main.js like below:
<script type="text/babel">
export default {
name: 'profile',
data: function () {
return {
user: {},
friends: []
}
},
methods: {
// Some methods
},
created: function () {
this.friends = this.$root.getFriends();
}
}
</script>
The problem arises when I refresh the current page. After page refresh, this.friends is null/undefined because this.$root.getFriends() is returning null/undefined. I can move it to user component, but I want to keep it in main.js so that GET call is used once and data will be available to the whole application.
Any input regarding how to solve this issue would be great. I am using Vue 2.0.1
Really, what you want to do, is pass the data the component needs as props.
The dirt simple easiest way to do it is this.
<router-view class="router-view" :friends="friends"></router-view>
And in your profile component,
export default {
props:["friends"],
name: 'profile',
data: function () {
return {
user: {},
friends: []
}
},
methods: {
// Some methods
}
}
If you want to get more sophisticated, the later versions of VueRouter allow you to pass properties to routes in several ways.
Finally, there's always Vuex or some other state management tool if your application gets complex enough.
The problem is that when you refresh the page, the whole app reloads, which includes the get, which is asynchronous. The router figures out that it needs to render details, so that component loads, and calls getFriends, but the asynchronous get hasn't finished.
You could work around this by saving and pulling the Promise from the get, but Bert's answer is correct: the Vue Way is to send data as props, not to have children pull it from parents.