How to transfer state between pages in multipage vue app? - javascript

I want to transfer data between pages in multipage vue app. I tried vuex with store but it's not working.
I used vue.config.js file to make multipage app. each page has App.vue and main.js to itself. When I import store.js to main.js, Initiate it there and it works only for it's own App.vue. But I need to transfer data from one page to another page. from one App.vue to another App.vue.
(Eg:- when I click on a person's name on one page, it should load that person's profile with his details. (It is an another page)). My plan was when someone click on the profile picture, details about that person goes to the store and I wanted to retrieve them in profile page. It didn't work. I'm a newbie to Vue. Am I doing it wrong way? Is there a better way doing this? Could someone help me to make this success? Thank you!
ps- Database is also attached. If there is a way to pass the reference between pages that will work too.
part of vue.config.js
module.exports = {
pages: {
'index': {
entry: './src/pages/home/main.js',
template: 'public/index.html',
title: 'Home',
chunks: [ 'chunk-vendors', 'chunk-common', 'index' ]
},
'register': {
entry: './src/pages/register/main.js',
template: 'public/index.html',
title: 'Register',
chunks: [ 'chunk-vendors', 'chunk-common', 'register' ]
},
'login': {
entry: './src/pages/login/main.js',
template: 'public/index.html',
title: 'Login',
chunks: [ 'chunk-vendors', 'chunk-common', 'login' ]
},
store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export const store = new Vuex.Store({
state:{
//this is not real data
i:0
},
Part of my code editor's file stack to get a better idea
I followed the method in below thread to make a multipage app
https://stackoverflow.com/questions/51692018/multiple-pages-in-vue-js-cli

If you want to have the same Vuex store using your app in different tabs try to use vuex persisted state plugin. Plugin would save your store in localStorage and that would give you possibility to share the same store between different tabs (or different instances of your app if you wish).

Related

In Angular, how can one component to have multiple HTML templates?

I am developing an ecommerce application, and one major feature is that this app should have multiple themes. The total number of themes could be 100 or even more. However, these themes all have the same data (For example: all home page have same banner images, new product, feature product data.) .
I know I can use ng-template or TemplateRef to determine which piece of HTML should display. But since I have over 100 themes, both ng-template or TemplateRef methods will load a lot of extra files. So I think I need some sort of lazy load, when a component loads the data then lazy loads the correct HTML template. So how can I have this work?
Looks like it is possible, all our routes are handled by lazy loaded modules. This is our out-of-the-box route config:
const routes: Routes = [
{ path: '', loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule) }
];
While module lazy has this route config:
const routes: Routes = [
{ path: 'home', component: HomeComponent },
]
While HomeComponent is taken from the declarations of module lazy.
Then define another module, called for example lazy-two with the same route config, and its own HomeComponent.
Finally, you can switch between the modules by using this code:
lazyLoad() {
const routes: Routes = [
{
path: '',
loadChildren: () => import('./lazy-two/lazy-two.module')
.then(m => m.LazyTwoModule)
}
];
this.router.resetConfig(routes);
this.router.navigateByUrl('/home');
}
This will lazy load module lazy-two and refresh the route to /home - you will see the component of the new module displayed.
I couldn't create a stackblitz, some errors occurred probably because of lazy loading. So I ran it locally on my machine and pushed the code to GitHub
EDIT I managed to make a StackBlitz
I recommend used ComponentFactoryResolver to create the components that you need to render.
this.templates = [
{
id: "template-1",
component: Template1,
},
{
id: "template-2",
component: Template2,
},
];
ngOnInit() {
this.templates.forEach((element) => {
this.containerReference.createComponent(
this.factoryResolver.resolveComponentFactory(element.component)
);
});
}
in the .html you should have
<ng-container #containerReference><ng-container>
what about using the same component and styling it different when you select the template?

How to redirect to a specific page of Vue-app via Flask

I'm building an app that has a page which ends in '#' provides some meta info for the page without '#', for example if the page '/user/aabb' has info about the user 'aabb', then the page '/user/aabb#' is the meta page for that user.
The problem is, '/aabb' part doesn't really exist because the app is SPA. 'aabb' is simply delivered as a prop for the component used in '/user' routing. Nor I can directly access '/user/aabb#' in the same context.
So is there a way for Flask to render a specific page of a Vue-build app? so that if the user enters '/user/aabb' on the address bar it links into '/user' page with 'aabb' prop. If there is, I guess the following functionalities should be required.
Flask to redirect to a specific page inside of Vue-route.
Flask to send data to the vue-component of that page.
Vue to receive the data from Flask.
Or is there any other ways to solve this... issue?
Thanks in advance.
The solution to all your questions is to use Vue Router with HTML5 History Mode.
As I mentioned in your last question, set up your Flask app to use the Vue SPA as the front-end
#app.route('/', defaults={'path': ''})
#app.route('/<path:path>')
def catch_all(path):
return app.send_static_file("index.html")
Then set up a router for your front-end URLs
// router.js
import Router from "vue-router"
import Vue from "vue"
Vue.use(Router)
export default new Router({
base: "/", // this should match the root path for your app
mode: "history",
routes: [{
name: "UserMeta",
path: "/user/:username#",
component: () => import("./path/to/UserMeta.vue"),
props: true
}, {
name: "User",
path: "/user/:username",
component: () => import("./path/to/User.vue"),
props: true
}]
})
You have to make the #-suffixed meta routes are listed before the normal pages in order to guarantee it doesn't think the username ends in #. See Matching Priority.
In the example above, both components receive the username route parameter as a prop.
You can then use one of the Data Fetching methods to load data into your components from your Flask API when your routes are loaded.
For example, using Fetching After Navigation and assuming you have a Flask app route for /api/user/<username>...
<template>
<div>
<div v-if="user">
<!-- show user details here -->
</div>
<div v-else>Loading...</div>
<//div>
</template>
<script>
export default {
name: "User",
props: { username: String },
data: () => ({ user: null }),
async created () {
const res = await fetch(`/api/user/${encodeURIComponent(this.username)}`)
this.user = await res.json()
}
}
</script>

How to define new router?

For this question I am referring to the vuestic-admin template from https://github.com/epicmaxco/vuestic-admin
This template is the most suitable template for me. However, I want to make some changes. To be exactly, I want to add a new page, but dont want this page shown in the sidebar. To do this I need to define new router. My problem is: I dont quite understand how to add new router.
Hier is what I have done:
Firstly, I made a .vue file in components/contact/Contact.vue. Its code:
<template>
<div class="contact">
<div class="row">
<div class="col-md-12">
<p>contact</p>
</div>
</div>
</div>
</template>
<script>
export default { name: 'contact' }
</script>
<style lang="scss"></style>
Secondly, I added a new .js file in store/modules/contact.js. Its code:
import lazyLoading from './lazyLoading'
export default {
name: 'Contact',
path: '/contact',
component: lazyLoading('contact/Contact'),
meta: {
default: false,
title: 'menu.contact',
iconClass: 'vuestic-icon vuestic-icon-extras'
}
}
Thirdly, in the store/modules/menu/index.js file, I changed the state defination by adding pages:
import contact from './contact'
const state = {
pages: [
contact
],
items: [
dashboard,
statistics,
forms,
tables,
ui,
extra,
auth
]
}
Fourthly, in router/index.js file, I made following changes:
export default new Router({
routes: [
...generateRoutesFromMenu(menuModule.state.items),
{path: '*', redirect: { name: getDefaultRoute(menuModule.state.items).name }},
...generateRoutesFromMenu(menuModule.state.pages),
{path: '*', redirect: { name: getDefaultRoute(menuModule.state.pages).name }}
]
})
By compiling the changes above I get the console error: Uncaught TypeError: Cannot read property 'name' of undefined
Based on my knowledge (and my guess) the problem should be in the fourth step.
Could anybody please show me a way out of this problem? Thanks a lot!
Looking at the source here for getDefaultRoute(),
function getDefaultRoute (menu = []) {
let defaultRoute
menu.forEach((item) => {
if (item.meta.default) {
defaultRoute = item
} else if (item.children) {
let defaultChild = item.children.find((i) => i.meta.default)
defaultRoute = defaultChild || defaultRoute
}
})
return defaultRoute
}
I would say that you don't need the line
{path: '*', redirect: { name: getDefaultRoute(menuModule.state.pages).name }}
since for contact you have set default: false and there are no children, which means the function returns null (hence the error message you received).
The framework seems to assume a single list of menu items and one of them to be set as default. But I think your approach should work.
The only potential problem is that it looks like you are changing framework code, which means a bit more work when upgrading to next version of the framework.
A note about upgrading
I just ran the basic install, and looking at the project I have to revise my remark about a potential upgrade problem.
Essentially, this is a template not a framework. The difference is that the installer creates starter code in your project's src folder, which you can freely modify and save to a github repository.
There is no package under node_modules that would overwrite your router changes when you run npm install on your project at a future date.
If epicmaxco create a new version of the template that you wish to use, you would simply create a new project and copy the changes you previously made within src to the new project (perhaps run a diff of the old and new src folders).

Vue with dynamic routes and components

Trying to build a test app to see if Vue is a suitable replacment for our AngularJS app. Trying to learn Vue at the same time.
After the user logs in we fetch some roles for that user. Base off those roles is how the menu gets built.
User1 { Role1, Role2, Role3}
In theory
User2 {Role1, Role3}
So Role1 would have a path of /start/page1 and page1 (component) and two child components.
Same with Role2 path of /start/page2 and page2 would have components on it.
I don't really want to build the routes until I know which roles the user has.
I'm using quasar-framework.org and using the menu slide out. Trying to create a menu on the fly. Seems like I need the components to already be imported?
I'm able to build the menu by looping through the roles and setting up a list of menus.
Trying to build the routes on the fly using this.$router.addRoutes(newRoute);
To do that I need the component to already be imported.
The Quasar way is load the components on the fly I guess.
In router.js
function loadPage (component) {
return () => import(`../../pages/${component}.vue`)
}
I can't seem to use that function in a method section.
Is this possible in Vue?
Take a look at vue-router lazy loading documentation and Quasar lazy loading documentation
You can't do it in a method, but if the user permission don't match the route permissions the component is never loaded, which is basically what you want.
Example
const routes = [
{
path: '/some-page-protected',
component: () => import('pages/SomePage'),
meta: {role: 'admin'}
}
]
Or
const SomePage = () => ('pages/SomePage')
const routes = [
{
path: '/some-page-protected',
component: SomePage,
meta: {role: 'admin'}
}
]

How can I get vue-router data into the parent template?

I have 2 route components:
1) A people product list component 2) A product detail component
The list shows the products and then there is a router-link to that product using history in the router definition/scope.
What I am trying to achieve is to get the data from the parent list routes into the child detail product template.
So I am working with vuex as I am storing the data in the store method. Below is the gist example with the setup I have got.
https://gist.github.com/mdunbavan/5cb756ff60e5c5efd4e5cd332dcffc04
The PeopleListing component works well and when clicking the router link it goes to the correct url and the data in the vue debug looks okay for vuex as below:
state:Object
currentProduct:undefined
products:Array[0]
route:Object
from:Object
fullPath:"/products/copy-of-long-shirt-dress-tudor"
hash:""
meta:Object (empty)
name:"product"
params:Object
path:"/products/copy-of-long-shirt-dress-tudor"
query:Object (empty)
What I am trying to do is basically render the data so it shows the router data within the homepage still and not look like it is going to another page which is what it is doing at the moment. The journey I am looking to create is as follows:
1) index page renders the PeopleListing
2) when clicking the it opens some animation within that template
3) the animation then renders the data from that clicked route such as '/products/the-product-title'
On point 3) we have to try and get all data attributes from that object.
Is it possible with the setup that I have got in my gist?
Thanks in advance!!
'product/:handle' is a child route for the '/' route, as you want to nest them.
Your router should look like this.
As you want to pass data to your route using params.
When props is set to true, the route.params will be set as the component props.
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/', component: PeopleListing,
children: [
{ name: 'product', path: '/products/:handle', component: ProductDetail, props: true }
]
},
]
});

Categories

Resources