Can Vue apps be nested? - vue.js

I have a monolithic SPA that I'm trying to modularize. The first step was breaking down into individual vue apps. Now I'd like to introduce Vue router and hence need to use Vue components. My main component is still nothing more than a wrapper around two Vue apps.
Is it possible to nest Vue apps inside a component or do I need to convert these apps into components even if they are really singletons and no multi-use is intended?
So basically, is something like this possible where sub-app-N are Vue apps similar to the app main app:
<div id="app">
<nav>
<router-link to="/">Main</router-link>
<router-link to="/settings">Settings</router-link>
</nav>
<router-view></router-view>
</div>
<script type="text/x-template" id="main-template">
<div>
<div id="sub-app-1"></div>
<div id="sub-app-2"></div>
</div>
</script>
<script>
const routes = [
{ path: "/", component: main },
{ path: "/settings", component: settings },
];
const router = new VueRouter({
routes // short for `routes: routes`
});
const app = new Vue({
router
}).$mount('#app');
const subapp1 = new Vue({
el: '#sub-app-1',
...
});
const subapp2 = new Vue({
el: '#sub-app-2',
...
});
</script>

Related

vue instance with child vue instance possible or alternative approach?

I would like to develop a vuejs multitouch app for a 4K display. It’s about 3-4 cards that are on a background and actually show the same content. For each of the cards a different entry page is visible.
Is it possible to pack several other instances (with the same content) of vuejs in divs within a Vue instance?
Somehow I would like to integrate an instance with store and router multiple times, but I can’t figure it out.
It would be helpful if someone can help me here, maybe provide a link or an approach.
I am looking for an approach how I can display the same content 3 times at the same time, at best with routes and nested routes. Each User can navigate separately, everyone has their own history via GUI.
when I try to use 2 instance inside the main vue instance 3 different routers, it’s always renders the content of main route.
I found this example where to instances are side by side, works great: https://jsfiddle.net/m91e7s2v/
but not inside a parent instance? why?
inside app.vue
<div id="app">
<VueToolMultitouch class="schatten" :startX="100" :startY="100" :startColor='"#00FF00"' id="id1" :idName="'id1'" :startZ="2">
<div id="subapp1">
<router-link to="/">/home</router-link>
<router-link to="/foo">/foo</router-link>
<p>Route path: {{ $route.path }}</p>
<router-view></router-view>
</div>
<h2>Passing Text 1</h2>
</VueToolMultitouch>
<VueToolMultitouch class="schatten" :startX="200" :startY="600" :startColor='"#FF0000"' id="id2" :idName="'id2'" :startZ="3">
<div id="subapp2">
<router-link to="/">/home</router-link>
<router-link to="/foo">/foo</router-link>
<p>Route path: {{ $route.path }}</p>
<router-view></router-view>
</div>
<h2>Passing Text 2</h2>
</VueToolMultitouch>
</div>
inside main.js
import router1 from "./router/router";
import router1 from "./router/router-1";
import router2 from "./router/router-2";
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
new Vue({
router: router1,
}).$mount("#subapp1");
new Vue({
router: router2,
}).$mount("#subapp2");
An alternative would be if everything is implemented with a single vue instance, but each of the cards gets its own "router".
maybe someone has an idea what that might look like.
The problem is that every child gets bound to the parent vue app and its prototype, this overrides the router of the children. I think that you'll need either to use iframes for the children or make the parent app handle with state the children views.
Edit:
I just learned about v-pre, this directive prevents Vue from "compiling" an HTML node and it's children.
You can basically have as many Vue instances even if they're nested as long as you put v-pre on the tag you use to mount the child Vue app.
Here's a working fiddle https://jsfiddle.net/dja36s7x/18/
I found an alternative way in the VueJS forum.
<div id="app">
<div class="row">
<my-child1></my-child1>
<my-child2></my-child2>
</div>
<div class="row">
<my-child3></my-child3>
<my-child4></my-child4>
</div>
</div>
const routes = [
{
path: '/page1',
component: { template: '<p>Page 1</p>' }
}, {
path: '/page2',
component: { template: '<p>Page 2</p>' }
}, {
path: '/page3',
component: { template: '<p>Page 3</p>' }
}
]
const MyChild = {
template: `
<div>
<router-link to="/page1">Page 1</router-link>
<router-link to="/page2">Page 2</router-link>
<router-link to="/page3">Page 3</router-link>
<button #click="$router.back()">Back</button>
<div>{{ $route.path }}</div>
<router-view />
</div>
`
}
function getChild() {
return {
extends: MyChild,
router: new VueRouter({
mode: 'abstract',
routes
})
}
}
new Vue({
components: {
MyChild1: getChild(),
MyChild2: getChild(),
MyChild3: getChild(),
MyChild4: getChild()
}
}).$mount('#app')
JSFiddle Example
Here, the components are expanded with their own router.
I currently no longer need the route via nested instances. but i will test the v-pre on everyone.
It seems this might be achieved using a hierarchy of components. If you're sure you need different Vue app instances, then it's worth going with Vue 3 as it's abandoned the idea of a shared global config, allowing you to create many Vue instances with createApp. All with different configurations.
You could do something like this (JS Fiddle here):
Vue.createApp({
name: 'App',
template: `
<h1>Primary App</h1>
<div id="subAppOne"></div>
<div id="subAppTwo"></div>
<div id="subAppThree"></div>
`
}).mount('#app');
Vue.createApp({
name: 'AppOne',
template: `<h2>App One</h2>`,
}).mount('#subAppOne');
Vue.createApp({
name: 'AppTwo',
template: `<h2>App Two</h2>`,
}).mount('#subAppTwo');
Vue.createApp({
name: 'App Three',
template: `<h2>App Three</h2>`,
}).mount('#subAppThree');
You can specify different routers with .use() on each app instance, just before calling mount().
const routerOne = VueRouter.createRouter({
history: VueRouter.createWebHistory(),
routes: [/* … */],
});
Vue.createApp({/* … */}).use(routerOne).mount('#appOne');

How do I do an on-click method on a button that directs to another component?

I have two sign up components that contain forms, one for those signing up as individuals and one signing up as businesses, I have a main page component with two large buttons labeled, "Click here to sign up as an individual", "Click here to sign up as a business'. How do I link these components on Vue? I am hoping that upon click of the button the component renders on the same page and not a new tab.
Thanks in advance!
So far,
Attempted to configure the router.js(I have a feeling this might be where my issue is)
Added the routes to the v-button
App.vue
<template>
<v-app>
<v-btn dark to="./components/CompanySignUp"> Sign up as a Company </v-btn>
<v-btn dark to="./components/FreelanceSignUp"> Sign up as a Freelancer
</v-btn>
</v-app>
</template>
<script>
export default {
name: "App",
components: {},
data: () => ({
//
})
};
</script>
router.js
import Vue from "vue";
import Router from "vue-router";
import CommpanySignUp from "./components/CompanySignUp";
import FreelancerSignUp from "./components/FreelancerSignUp";
Vue.use(Router);
const router = new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "./components/CompanySignUp",
name: "Company Sign Up",
component: CommpanySignUp
},
{
path: "./components/FreelancerSignUp",
name: "Freelancer Sign Up",
component: FreelancerSignUp
}
]
});
main.js
import Vue from "vue";
import App from "./App.vue";
import vuetify from "./plugins/vuetify";
import 'material-design-icons-iconfont/dist/material-design-icons.css'
import VueRouter from "vue-router";
Vue.use(VueRouter);
Vue.config.productionTip = false;
new Vue({
vuetify,
render: h => h(App)
}).$mount("#app");
This sounds like a good opportunity to use vue-router, but there are multiple approaches to this problem. Depending on scope, there may be more than one good answer. There is a comment above about using emitters and props, which is fine, but I would recommend using vue-router because it's made for this kind of dynamic component switching. If you've used the vue-cli it should be trivial to add, but the following example uses the standalone CDNs for brevity. This can all be done in separate files and the vue-cli will already have a nice scaffold for you if you want to see how that's done.
const Main = {
template: `
<div>
<router-link to="/register/business">Register for business</router-link>
<router-link to="/register/personal">Register for personal</router-link>
</div>
`
};
const RegistrationPage = { template: '<router-view></router-view>' };
const BusinessRegistration = {
template: `
<h1>Business</h1>
`
};
const PersonalRegistration = {
template: `
<h1>Personal</h1>
`
};
const routes = [
{
path: '/',
component: Main
},
{
path: '/register',
component: RegistrationPage,
children: [
{
path: 'business',
component: BusinessRegistration
},
{
path: 'personal',
component: PersonalRegistration
}
]
}
];
const router = new VueRouter({
routes
});
const app = new Vue({
router
}).$mount('#app');
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://unpkg.com/vue-router#2.0.0/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<router-view></router-view>
</div>
</body>
</html>
There are multiple benefits to this approach:
Vue router is supported pretty well by the Vue community so you can find lots of documentation and examples.
Your end user can visit mysite.com/register/business and land on the correct page, rather than having to go through clicking on the button if they decide to leave your page and come back.
Much of the logic is abstracted away by the library rather than having to do complex conditional logic and event emitters.
This is a very simple example that relies heavily on the "getting started" docs here. If you did start your project with the vue-cli, you should be able to run vue add vue-router, which should do some setup for you if you missed that step in the project creation process, otherwise you can use npm and set things up manually.
Assuming that your vue router is already working and you already displayed your component What you did is already correct, just follow these steps to make it working.
First put a router view in your main app . like below
<v-app>
<v-btn dark to="./components/CompanySignUp"> Sign up as a Company </v-btn>
<v-btn dark to="./components/FreelanceSignUp"> Sign up as a Freelancer
</v-btn>
<router-view></router-view>
</v-app>
Second change your route name into this one, this route name will be use to call you component itself.
{
path: "./components/CompanySignUp",
name: "company_sign_up",
component: CommpanySignUp
},
Lastly in your main, the final structrue is like this
<v-app>
<v-btn dark to="{name:'company_sign_up'}"> Sign up as a Company </v-btn>
<v-btn dark to="{name:'freelancer_sign_up'}"> Sign up as a Freelancer
</v-btn>
<router-view></router-view>
</v-app>
You have your router.js file defined correctly but you never included it in your app. Instead, you initialized another (empty) router in main.js. Just import your router.js and then include it in your initialization of the app.
import router from 'router.js'; <--- your file
new Vue({
router, <--------- apply router
render: h => h(App)
}).$mount("#app");
The last thing left is to define a place for the router components to render. That is accomplished by placing a <router-view> compenent somewhere in your app template.
<template>
<v-app>
<v-btn dark to="./components/CompanySignUp"> Sign up as a Company </v-btn>
<v-btn dark to="./components/FreelanceSignUp"> Sign up as a Freelancer
</v-btn>
<router-view></router-view> <------------- component rendered here
</v-app>
</template>
For maintenance reasons, consider using the name parameter for the :to prop so you can minimize code changes if you ever need to update the path.

Vue router. Root Vue has no data?

I'm trying to get my head round vue-router. I'm used to instantiating Vue like this...
vm = new Vue({
el : '#vueRoot',
data : { msg : 'hello' }
...
})
Now I'm being asked to instantiate it passing the router...
vm = new Vue({
router
}).$mount('#vueRoot');
My question is where do I put my data or methods, or whatever other Vue properties I would normally use? I see that my root Vue can have markup, with router-link elements. Am I to understand that, once I use the router, everything should be in components?
You can use your default notation:
new Vue({
el: '#app',
router,
template: '<MyApp/>',
components: { MyApp }
})
But you must have a <router-view/> Element in your template.
In your Main.js
window.Vue = require('vue');
import VueRouter from 'vue-router'
import Overview from '../components/Overview.vue';
import Sale from '../components/Sale.vue';
Vue.use(VueRouter);
let routes = [
{path: '/home', component: Overview,name:'Overview'},
{path: '/sale', component: Sale, name:'Sale'},
];
const router = new VueRouter({
mode: 'history',
routes
});
const app = new Vue({
el: '#vueRoot',
router,
});
In your Root View place element
<router-view></router-view>
In your links
<router-link to="/sale" class="nav-link">
<i class="nav-icon fas fa-cart-plus "></i>
<p>
Point of Sale
</p>
</router-link>
In your Views
<template>
<v-app>
{{viewTitle}}
{{viewSubtitle}}
</v-app>
</template>
<script>
export default {
data() {
return {
viewTitle:'Home',
viewSubtitle:'description',
}
},
methods: {
YourMethod_1() {
},
YourMethod_2() {
},
}
}
</script>
This is how the latest versions of Vue.js works with router
import App from './App';
import VueRouter from 'vue-router';
import {routes} from './routes';
const router = new VueRouter({
routes,
mode: "history", // you can remove this if not required
});
new Vue({
el: '#app',
router,
render: h => h(App)
});
routes.js
export const routes = [
// your components as objects
]
App.vue
<template>
<div>
<router-view/>
</div>
</template>
<script>
export default {
name: "App"
}
</script>

Setting up Vue router in Vue2 using the script tag only.like angular 1.x router

I need to set up vue router in my vue ja 2 application .I am not using vue cli just the cdn for vue Js .I am not able to find a way of how to set up vue router with cdn.can anyone suggest any documentation or the technique of how to achieve that ??
Any help would be much appreciated
Here's a bare bones example to help get going:
<html>
<head>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vue-router#2.0.0/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<p><router-link to="/page1">Go to Page 1</router-link></p>
<p><router-link to="/page2">Go to Page 2</router-link></p>
<p><router-view></router-view></p>
</div>
<script>
var PageTwoComponent = Vue.component('comp2',{
template: '<p>Component Two</p>'
})
var PageOneComponent = Vue.component('comp1',{
template: '<p>Component One</p>'
})
const routes = [
{path: '/page1', component: PageTwoComponent},
{path: '/page2', component: PageOneComponent}
]
const router = new VueRouter({
routes
})
var app = new Vue({
router
}).$mount('#app')
</script>
</body>
</html>

Install VueRouter with Vue-Cli Webpack

I created a fresh project using the vue-cli command:
vue init webpack myapp
I am trying to add the vue-router to handle routes but I am having trouble.
Here is my main.js:
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App'
var Foo = Vue.extend({
template: '<p>This is foo!</p>'
})
var Bar = Vue.extend({
template: '<p>This is bar!</p>'
})
Vue.use(VueRouter)
const router = new VueRouter()
router.map({
'/foo': {
component: Foo
},
'/bar': {
component: Bar
}
})
router.start(App, '#app')
/* eslint-disable no-new */
new Vue({
el: 'body',
components: { App }
}).$mount('#app')
Here is my index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>shivaminyanim.com</title>
</head>
<body>
<app></app>
<!-- built files will be auto injected -->
</body>
</html>
And here is my App.vue:
<template>
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- use v-link directive for navigation. -->
<a v-link="{ path: '/foo' }">Go to Foo</a>
<a v-link="{ path: '/bar' }">Go to Bar</a>
</p>
<!-- route outlet -->
<router-view></router-view>
</div>
</template>
Whatever I do I can't seem to figure out how to get it to work. Right now I don't get any console errors but the browser just displays
Cannot GET /foo
for every route respectively.
I am currently using
"vue": "^1.0.21"
"vue-router": "^0.7.13",
How can I get started with vue-router?
You need to add router to your bootstrapped Vue instance in main.js. For example like this:
Vue 2.0 and Vue-router 2.0
new Vue({
router,
el: '#app',
render: h => h(App)
})
Vue 1.0 and Vue-router < 2.0
router.start({
components: { App }
}, '#app')