vue instance with child vue instance possible or alternative approach? - vue.js

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');

Related

Vue props undefined on component

I am struggling with passing props to my child component and reading through many many examples, there are quiet a few in my position. Seems this shouldn't be so complicated, right?
Ideally, when I drop my component on a html page I want to be able to pass a url as an attribute. Example
<landingpage myUrl="http://localhost"><landingpage> but when I inspect with the Vue Dev Tools in browser, it is always undefined. I've seen a hack using JQuery to select the element and then get the attribute but I would like to do it in pure Vue.
In my code below, no variation of "title" is passed to my component.
In my index.html page I have this
<body>
<p>Hello world, this is some text. Howdy.</p>
<div id="NewWidget">
<div id="app" data-title="mario" :data-title="luigi" :title="princess">
<landingpage title="hello!" :title="spaghetti" v-bind:title="Nervos"></landingpage>
</div>
</div>
<!-- built files will be auto injected -->
</body>
In my App.vue I have
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
And in my landingpage.vue I have this
export default {
name: 'landingpage',
data () {
return {
categories: [],
}
},
props: {
title: {
type: String
}
},
...
My router index.js
export default new Router({
routes: [
{
path: '/',
name: 'LandingPage',
component: LandingPage,
props: true
},
...
In my LandingPage component, this.title is always null/undefined.
I am using Vue 2.5.2 / Vue Router 3.0.1
Only thing I can think of is my VueRouter usage in App.vue is burning the props?

Can Vue apps be nested?

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>

Passing ID through router-link in Vue.js

I have 2 router links that link to the same page (definition page) but has different ids, in my definition page I have an if else loop that checks the id and then posts the apropriate definition for that id.my problem is that my loop can't properly read my id and goes straight to my else statment, this is the closest that I've gotten it to work.
My 2 router-links in page 1
<router-link :to="{ path: '/Pulse/Definition',id:'Alignment'}" v-bind:tooltip="Alignment" append><a >Read more ></a></router-link>
<router-link :to="{ path: '/Pulse/Definition'}" id="Trust" append><a >Read more ></a></router-link>
My definition page
<template>
<div class="PulseDefinition page row">
<h2 v-if=" id=='Alignment'">hello world {{id}}</h2>
<h2 v-else-if=" id=='Trust'">hello world {{id}}</h2>
<h2 v-else>Sorry try again</h2>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.PulseDefinition{
margin-top:2.5rem;
margin-left:3rem;
background-color: aquamarine;
width:50rem;
height:50rem;
}
</style>
Router
import Vue from 'vue';
import Router from 'vue-router';
import Community from '../components/PulseCommunity';
import Home from '../components/Home';
import Definition from '../components/Definition.vue';
Vue.use(Router)
export default new Router({
routes:[
{
path:'Tuba',
name:'Tuba',
component: Default
},
{
path:'/Pulse',
name:'Pulse',
component:PulseNav,
children:[{
path:'/Pulse/Overview',
name:'Overview',
component:Overview
},
{
path:'/Pulse/Personal',
name:'Personal',
component:Personal
},
{
path:'/Pulse/Community',
name:'Community',
component:Community
},
{
path:'/Pulse/Definition/:id',
name:'Pulse Definition',
component:Definition
}
]
},
{
path:'/Coaching',
name:'Coaching',
component:Coaching
},
{
path:'/Comunication',
name:'Comunication',
component:Comunication
},
{
path:'/Home',
name:'Home',
component:Home
},
]
})
Normally when your using the router inside of a Vue application you'll want to use route parameters, check out the dynamic routing link here.
Using the same example:
const router = new VueRouter({
routes: [
// dynamic segments start with a colon
{ path: '/user/:id', component: User }
]
})
Here in our router whenever we navigate to a url where /user/ is present providing we then add something after we can match the /:id section of it. Then inside of our component we are able to query the parameters for the ID that was sent in our url:
console.log(this.$route.query.id)
Using this we could then save that value into our component or we could build reactivity around this.$route.query.
In your case you'd only need to append to the string that you pass into that router link by simply using your data / methods or if you require further rules you could use a computed method. This might become or something simmilar:
<router-link :to="{ path: '/Pulse/Definition'+ this.alignmentType}" v-bind:tooltip="Alignment" append><a >Read more ></a></router-link>
i found a solution thx to the help of li x and a senior coworker of mine,here is the awnser.
my working router-link in page 1
<router-link :to="{ path: '/Pulse/Definition/'+'Alignment'}" v-bind:tooltip="Alignment" append><a >Read more ></a></router-link>
im adding the id(Alignment) to my url with[:to="{ path: '/Pulse/Definition/'+'Alignment'}"]
my definition page
<template>
<div class="PulseDefinition page row">
<h2 v-if=" this.$route.params.id=='Alignment'">hello world {{this.$route.params.id}}</h2>
<h2 v-else-if=" this.$route.params.id=='Trust'">hello world {{this.$route.params.id}}</h2>
<h2 v-else-if=" this.$route.params.id=='undefined'">Sorry try again {{this.$route.params.id}}</h2>
<h2 v-else>XXXSorry try againXXX{{this.$route.params.id}}</h2>
<!-- {{console.log("hi")}} -->
</div>
</template>
<script>
// console.log(this.$route.query.id);
export default {
}
</script>
im using [this.$route.params.id] to retrieve my id, and my router page stayed the same.
thank you all for the great help ;)

vue-router this.$route.params is empty

I'm trying to get a variable called project_id from the address bar using vue-router. I've initialized a router like so:
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App'
Vue.config.productionTip = false
Vue.use(VueRouter)
/* eslint-disable no-new */
const router = new VueRouter({
routes: [
{ path: '/project/:project_id', component: App }
]
})
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
And tried to access this.$route.params.project_id from within my App.vue componenet:
<template>
<div id="app">
<img src="./assets/logo.png">
<div id="center_bar">
oh: {{this.$route.params.project_id}}
</div>
</div>
</template>
<script>
import ProjectList from './components/ProjectList'
import ProjectAboutBox from './components/ProjectAboutBox'
export default {
name: 'App',
created() {
console.dir(this.$route.params)
},
components: {
ProjectList,
ProjectAboutBox
}
}
</script>
However, when I write this.$route.params to the console, I see that it is an empty object.
I didn't see anyone who encountered something similar, so my guess is that I'm missing something very basic, but I can't figure out exactly what it is.
In addition, if I console.dir(this.$route) I'm seeing that fullPath is "/", even though I'm accessing http://localhost:8080/project/kljkjkj/
EDIT:
I have also found that when I create a <router-link> that leads to the address I want to parse, then clicking on it make the whole thing work, just accessing it directly by typing the address in the address bar fails
I come across a similar problem.
When manually enter url or refresh the browser, the $route object is not populated.
After some investigation, I found that if a lazy-loading route is matched:
For components outside 'router-view':
the $route object is not being populated even in the 'mounted' hook, but is populated later in the rendering process.
For components inside 'router-view':
the $route object is populated and available immediately
My fix is to use 'computed' property instead of 'data' when try to access variable inside the $route object.
Version:
"vue": "^2.6.11",
"vue-router": "^3.2.0"
Node: Changing the mode from 'hash' to 'history' doesn't help in my case.
Default vue-router is hash mode. You can try visit http://localhost:8080/#/project/kljkjkj/
You can change to history mode
const router = new VueRouter({
mode: 'history',
routes: [{ path: "/project/:project_id", component: App }]
});
Demo: https://codesandbox.io/s/p9v3172x6j (try to change url to https://p9v3172x6j.codesandbox.io/project/1234)
when in <template>you don't need to refer this.
have you tried:
<template>
<div id="app">
<img src="./assets/logo.png">
<div id="center_bar">
oh: {{$route.params.project_id}}
</div>
</div>
</template>
?
Also, I see that you are not using a <router-view>:
https://router.vuejs.org/api/#router-view

vue-router doesn't recognize $ref from a component after routing

I'm new with Vuejs and vue-router I've been reading a lot View documentation and forums to figure this out.
I can make my routing working well. But I can't (easily) the "ref" from the content that was routed.
I say "easily" because I found on "this.$children[0].$children[0].$refs" which doesn't look correct to me and also difficult to maintain.
What I would like is to have easy way like "this.$refs" or "this.router["foo"].$refs".
I'll paste the vue documentation basic example with "ref" in the elements.
HTML
<div id="app">
<h1 ref="myrefInitial">Hello App!</h1>
<p>
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<router-view></router-view>
<p>
refs founds: {{getAllRefs}}
</p>
</div>
<script src="index.js"></script>
JS
const Foo = {
template: '<div ref="myrefFoo">foo</div>'
}
const Bar = {
template: '<div ref="myrefBar">bar</div>'
}
const routes = [{
path: '/foo',
component: Foo
},
{
path: '/bar',
component: Bar
}
]
const router = new VueRouter({
routes // short for `routes: routes`
})
router.afterEach((to, from) => {
console.log("going to " + to.fullPath)
console.log(to);
router.app.getAllRefs();
})
const app = new Vue({
router,
computed: {
getAllRefs: function(){
return this.$refs
}
}
}).$mount('#app')
JsFiddle example
https://jsfiddle.net/3rdSenna/kaqqsrob/
In the end I wrote a simple For loop to dig on every $refs and find the child $refs name until is matched. It solved my problem.
But I believe the suggestion from #rinatdobr would suite me well.