I'm fairly new to vue.js and trying to build an SPA. Basicly i define all routes from my backend with an alias to my API endpoints. a lot of them using the same component. Data gets fetched with router.beforeEach and vue-resource.
Now when i navigate from a route to another route which share the same template, my router-view doens't get updated.
Here's my code:
<script>
var data = {
content: null
}
const site = {
template:'<div>{{this.title}}</div>',
data: function () {
return data.content.body
}
}
const home = {
template:'<div>{{this.title}}</div>',
data: function () {
return data.content.body
}
}
const routes = [
{ path: '/api/12.json', component: home, alias: '/' },
{ path: '/api/4.json', component: site, alias: '/projekte' },
{ path: '/api/5.json', component: site, alias: '/projekte/projekt-1' },
{ path: '/api/7.json', component: site, alias: '/projekte/projekt-2' },
{ path: '/api/6.json', component: site, alias: '/projekte/projekt-3' },
{ path: '/api/8.json', component: site, alias: '/agentur' },
{ path: '/api/9.json', component: site, alias: '/lab' },
{ path: '/api/10.json', component: site, alias: '/kontakt' },
]
const router = new VueRouter({
routes
})
router.beforeEach((to, from, next) => {
Vue.http.get(to.matched[0].path).then((response) => {
data.content = response;
console.log(data.content);
next();
}, (response) => {
data.content = {
'body': {
'title': 'Error 404'
}
};
next();
});
})
const app = new Vue({
router
}).$mount('#app')
</script>
Your data object is not part of your Vue component. It is defined outside of your Vue app.
Even though your components - home and site returns the data.content.body object, your main data object is not part of Vue's reactivity system. Therefore, the changes in that data object are not tracked.
You can read more about it here: https://vuejs.org/guide/reactivity.html
To ensure that this does not happen, you need to define your data as part of your component itself. And you need to do your http calls as part of mounted hook on the route component, which has access to this.data of the component.
If you need to share data between components (most likely), then you need to use state management using vuex that allows you to have a shared state for the entire Vue app.
You can read more about Vuex here: http://vuex.vuejs.org/en/intro.html
Here's a working example of vue / vue-router / vuex / vue-resource example for API Calls. Thanks at Mani for the hint i needed.
const site = {
template:'<div>{{ content.title }}</div>',
computed: {
content (){
return store.state.routeContent
}
}
}
const home = {
template:'<div>{{ content.title }}</div>',
computed: {
content (){
return store.state.routeContent
}
}
}
const notFound = {
template: '<div>{{ content.title }}</div>',
computed: {
content (){
return store.state.routeContent
}
}
}
const routes = [
{ path: '/api/12.json', component: home, alias: '/' },
{ path: '/api/4.json', component: site, alias: '/projekte' },
{ path: '/api/5.json', component: site, alias: '/projekte/projekt-1' },
{ path: '/api/7.json', component: site, alias: '/projekte/projekt-2' },
{ path: '/api/6.json', component: site, alias: '/projekte/projekt-3' },
{ path: '/api/8.json', component: site, alias: '/agentur' },
{ path: '/api/9.json', component: site, alias: '/lab' },
{ path: '/api/10.json', component: site, alias: '/kontakt' },
{ path: '/*', component: notFound }
]
const store = new Vuex.Store({
state: {
routeContent: null
},
mutations: {
routeContent (state, payload) {
state.routeContent = payload
document.title = payload.title
}
}
})
const router = new VueRouter({
routes
})
router.beforeEach((to, from, next) => {
Vue.http.get(to.matched[0].path).then((response) => {
store.commit('routeContent', response.body)
next()
}, (response) => {
console.log(response);
errorObject = {
'title': 'Error 404'
},
store.commit('routeContent', errorObject)
next()
});
})
const app = new Vue({
router
}).$mount('#app')
Related
I have a standard set of Routes:
export const ROUTES: Routes = [
{
path: '', redirectTo: 'home'
},
{
path: 'notentitled', component: 'NotEntitledComponent'
},
{
path: 'welcome', component: 'WelcomeComponent', canActivate: [RoutingService]
},
{
path: 'active', component: 'ActiveComponent', canActivate: [RoutingService]
},
{
path: 'table', component: 'TableComponent', canActivate: [RoutingService]
},
{
path: '**', component : NotFoundComponent
}
];
The canActivate method pulls in the users entitlement credentials and checks the target route ie 'active' against their entitlement ie:
public canActivate(route: ActivateRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
let target = state.url;
return entitlementService.getUserInfo()
.pipe(
map(data => {
let canSeePage = data?.entitlements?['target'];
return canSeePage;
}),
catchError((error: any) => {
route.navigate(['notentitled']);
return of(false);
});
}
I want to add some logic to cater to a scenario. If in the entitlement check ie:
let canSeePage = data?.entitlements?['target'];
false; before returning false; check if user can see any other page and redirect there.
Example, user requests 'active' route, however, this fails:
let canSeePage = data?.entitlements?['target']; // ie data.entitlements.active: false
However, data.entitlements.table is true, so redirect to 'table'
My Requirement is From Backend I am getting routes as "app/dashboard?dashboard_id={id}"
How can I configure this in Module.ts file?
I tried using below
const routes: Routes = [
{
path: "app/dashboard/:dashboard_id",
component: AddEditComponent,
canActivate: [AuthGuard],
},
];
but I am getting errors like routes are not defined.
Can Someone Please Help me on that how can I configure this route as I need to catch this id as queryParams in Component.
You can do something like this:
const routes: Routes = [
{
path: "app/dashboard",
component: AddEditComponent,
canActivate: [AuthGuard],
children: [
{
path: ':dashboard_id'
component: NewComponentId
}
]
},
];
and in your NewComponentId you can do something like inside the constructor to catch the id:
this.route.paramMap.pipe(
map((paramMap) => {
if (paramMap.get('id') !== 'something') {
// your code
}
}),
Required Route param:
{path: 'users/:userId', component: UserComponent}
and get it from param:
constructor(params: RouteParams) {
var paramId = params.get("id");
}
Optional Route Param:
{ path: '/user', component: UserComponent }
its just define the route part and param pass by query string, to read the queryparam:
this.route.queryParams
.subscribe(params => {
console.log(params);
}
);
you must process the query string for this route: "app/dashboard?dashboard_id={id}"
Update:
To set the queryparam in routerlink use it this way:
<a routerLink="/dashboard" [queryParams]="{ dashboard_id: 11 }"
>another dashboard</a>
My '/' path redirect to '/loading' and I need to pass props like mysite/?demo=true and then that prop pass to the component attached to '/loading'
this is the router config
{
path: '/',
redirect: '/loading',
},
{
path: '/loading',
component: Loading
},
Do:
{
path: '/',
redirect: { path: '/loading', params: { default: true, demo: true } }
},
{
path: '/loading',
component: Loading
},
And in your Loading component, you define a prop called demo, like:
props: {
demo: Boolean,
}
Then you will be able to access this.demo and read true, wich is the value passed via route.
Building up on Mathew's solution, to access the route parameter, you could do this.$route.params.demo
I am trying to create a SPA which shows dealer in every state of austria. For example if a user visits example.com/vienna it shows every dealer in vienna. But if a users visits example.com/paris, he will still get directed to the dynamic route /paris but of course there will be nothing shown.
So my approach was to check if the state which the user wants to search for is available in the list of state and therefore directing it to the available state or redirect him to a 404 page.
If the state is available it works, but if I'll try to go to a non existing state I am stuck in a loop from next('/404')
export default new Router({
routes: [{
path: '/',
name: 'Home',
component: Home
},{
path: '/:region',
component: RegionQuery,
beforeEnter: (to, from, next) => {
let isRegion = false;
let allRegions = storeConfig.state.states;
let toRegion = to.params.region;
for(var i in allRegions){
if(allRegions[i].route === toRegion){
isRegion = true;
}
}
if (isRegion) {
next();
} else {
next('/404');
}
}
},
{
path: '/404',
name: '404',
component: NotFound
},
{
path: '*',
redirect: '/404'
},
],
})
What am I doing wrong or is there a better approach to my problem?
/404 is matched to /:region
You need to change your path order
export default new Router({
routes: [{
path: '/',
name: 'Home',
component: Home
},
{
path: '/404',
name: '404',
component: NotFound
},{
path: '/:region',
component: RegionQuery,
beforeEnter: (to, from, next) => {
let isRegion = false;
let allRegions = storeConfig.state.states;
let toRegion = to.params.region;
for(var i in allRegions){
if(allRegions[i].route === toRegion){
isRegion = true;
}
}
if (isRegion) {
next();
} else {
next('/404');
}
}
},
{
path: '*',
redirect: '/404'
},
]
First, I don't think this question is a duplication of this one. If it is, sorry.
I'm working on an angular 2 application. Few weeks ago, I was using the beta15. I've decided to update to rc1 for some reasons :
I prefer to update progressively instead of doing it one -long- time
Doing this, I have to keep an eye on the changelog
third parties follows the movement
Of course, I've encountered some issues, I've updated packages by hand
and clean my code.
But there is still an issue that I can't figure out. I have this error :
component does not have route configuration. I have nested routes.
The difference between the other issue is that my component isn't a child component, but the main component.
Here is my Routeconfig declaration (I'm using router-deprecated :
#RouteConfig([
{ path: '/home', name: 'Home', loader: () => Routes.lazyLoad('component#home', 'HomeComponent'), useAsDefault: true },
{ path: '/media/...', name: 'Media', loader: () => Routes.lazyLoad('component#media', 'MediaComponent') },
{ path: '/channel/...', name: 'Channel', loader: () => Routes.lazyLoad('component#channel', 'ChannelComponent') },
{ path: '/playlist', name: 'Playlist', loader: () => Routes.lazyLoad('component#home', 'HomeComponent') },
{ path: '/medias', name: 'Medias', loader: () => Routes.lazyLoad('component#medias', 'MediasComponent') },
])
export class MainComponent {
private prodEnv: boolean = initialState.prodEnv;
}
Routes.lazyload() is a really simple function that uses SystemJS to import components :
public static lazyLoad(ref: string, component: string): any {
return System.import(ref)
.then((m: any) => m[component])
.catch((err: any) => {
console.error(err);
return err;
});
}
Of course, Media and Channel also have a RouteConfig.
Here is the MediasComponents's RouteConfig
#RouteConfig([
{ path: 'add', name: 'Add', component: AddComponent, useAsDefault: true },
{ path: 'manage', name: 'Manage', component: ManageComponent },
{ path: 'edit/:id', name: 'Edit', component: EditComponent }
])
ChannelComponent :
#RouteConfig([
{ path: 'add', name: 'Add', component: AddComponent, useAsDefault: true },
{ path: 'manage', name: 'Manage', component: ManageComponent },
{ path: 'manage/:id', name: 'ManageId', component: ManageComponent },
{ path: 'edit/:id', name: 'Edit', component: EditComponent }
])