how to pass props to root App component in vuejs v3? - javascript

How can i pass some variable from the main div folder:
<div
id="app"
someVariable='some value'
></div>
and to have it as a prop in the main App component in VueJS v3.0:
name: "App",
components: {
},
props: {
someVariable: {
type: String,
default: "-"
}
}

You could not access that using props, but you could get the value of that attribute using some Vanilla js DOM like document.getElementById("app").getAttribute("someVariable")
const {
createApp
} = Vue;
const App = {
props: ["someVariable"],
data() {
return {
}
},
mounted() {
console.log(document.getElementById("app").getAttribute("someVariable"))
}
}
const app = createApp(App)
app.mount('#app')
<script src="https://unpkg.com/vue#3.0.0-rc.11/dist/vue.global.prod.js"></script>
<div id="app" someVariable='some value'>
Vue 3 app
</div>

Related

Showing muptiple components in an app by vue3

I made two components and tried to show these in vue3 app.
my code in html
<div id="app">
<image_preview>
URL: [[image]]
</image_preview>
<file_uploader>
Counter:[[counter]]
</file_uploader>
</div>
in javascript
const ImagePreview = {
data(){
return {
image:"test.png"
}
},
mounted() {
},
delimiters: ['[[', ']]']
}
const Counter = {
data() {
return{counter: 0}
},
mounted() {
setInterval(() => {
this.counter++
}, 1000)
},
delimiters: ['[[', ']]']
}
Vue.createApp({
components:{
"image_preview":ImagePreview,
"file_uploader":Counter
}
}).mount('#app')
However nothing appears in html
Where am I wrong?
please re-read vue's documentation on components you know if you're going to need a template to render components and I bet you haven't read vue's documentation on components
follow my example and it takes care of your problem:
// </script><script type="module">
import { createApp, ref, onMounted } from 'https://unpkg.com/vue#3/dist/vue.esm-browser.js'
const ImagePreview = {
template: '#image_preview',
setup() {
return {
image: 'test.png'
}
}
}
const Counter = {
template: '#file_uploader',
setup() {
const counter = ref(0)
onMounted(() => setInterval(() => counter.value++, 1_000))
return { counter }
}
}
const app = createApp({
components:{
"image_preview": ImagePreview,
"file_uploader": Counter
}
})
.mount('#app')
<div id="app">
<image_preview>
URL: [[image]]
</image_preview>
<file_uploader>
Counter:[[counter]]
</file_uploader>
</div>
<template id="image_preview">
URL: {{ image }}
</template>
<template id="file_uploader">
Counter: {{ counter }}
</template>

How to get $refs using Composition API in Vue3?

I am trying to get $refs in Vue 3 using Composition API. This is my template that has two child components and I need to get reference to one child component instance:
<template>
<comp-foo />
<comp-bar ref="table"/>
</template>
In my code I use Template Refs: ref is a special attribute, that allows us to obtain a direct reference to a specific DOM element or child component instance after it's mounted.
If I use Options API then I don't have any problems:
mounted() {
console.log("Mounted - ok");
console.log(this.$refs.table.temp());
}
However, using Composition API I get error:
setup() {
const that: any = getCurrentInstance();
onMounted(() => {
console.log("Mounted - ok");
console.log(that.$refs.table.temp());//ERROR that.$refs is undefined
});
return {};
}
Could anyone say how to do it using Composition API?
You need to create the ref const inside the setup then return it so it can be used in the html.
<template>
<div ref="table"/>
</template>
import { ref, onMounted } from 'vue';
setup() {
const table = ref(null);
onMounted(() => {
console.log(table.value);
});
return { table };
}
On Laravel Inertia:
<script setup>
import { ref, onMounted } from "vue";
// a list for testing
let items = [
{ id: 1, name: "item name 1" },
{ id: 2, name: "item name 2" },
{ id: 3, name: "item name 3" },
];
// this also works with a list of elements
let elements = ref(null);
// testing
onMounted(() => {
let all = elements.value;
let item1 = all[0];
let item2 = all[1];
let item3 = all[2];
console.log([all, item1, item2, item3]);
});
</script>
<template>
<div>
<!-- elements -->
<div v-for="(item, i) in items" ref="elements" :key="item.id">
<!-- element's content -->
<div>ID: {{ item.id }}</div>
<div>Name: {{ item.name }}</div>
</div>
</div>
</template>
<template>
<your-table ref="table"/>
...
</template>
<script>
import { ref, onMounted } from 'vue';
setup() {
const table = ref(null);
onMounted(() => {
table.value.addEventListener('click', () => console.log("Event happened"))
});
return { table };
}
</script>
Inside your other component you can interact with events you already registered on onMounted life cycle hook as with my example i've registered only one evnet
If you want, you can use getCurrentInstance() in the parent component like this code:
<template>
<MyCompo ref="table"></MyCompo>
</template>
<script>
import MyCompo from "#/components/MyCompo.vue"
import { ref, onMounted, getCurrentInstance } from 'vue'
export default {
components : {
MyCompo
},
setup(props, ctx) {
onMounted(() => {
getCurrentInstance().ctx.$refs.table.tempMethod()
});
}
}
</script>
And this is the code of child component (here I called it MyCompo):
<template>
<h1>this is MyCompo component</h1>
</template>
<script>
export default {
setup(props, ctx) {
const tempMethod = () => {
console.log("temporary method");
}
return {
tempMethod
}
},
}
</script>

vuejs both components get prop from App.js, but one component lost prop data

When I refresh my browser few times when I am on "ActorDetails.vue" page/component, not often but sometimes, I lost my actorsData prop data(should have array of 5 objects but become empty array), at first, I thought it's an API's problem but when I try to console.log() the data inside of "App.js", the data exist... I can't seem to find where the problem is.(Also I did try refresh the browser few times when I am on "ActorsList.vue" page/component, the prop data always exist)
Both pages/components("ActorList.vue" and "ActorDetails.vue") gets topActors data from "App.vue".
(Comments in code)
App.vue
<template>
<div id="app">
<router-view name="homePage" />
<router-view :actorsData="topActors" /> <== "ActorList.vue" and "ActorDetails.vue" use this "router-view"
<div class="over-limit-resolution">Over 4k</div>
</div>
</template>
<script>
import { getActors } from "./util/TheMoveDatabase";
export default {
name: "App",
data() {
return {
topActors: [],
};
},
created() {
getActors.then((result) => {
console.log(result); <== Data always came back from API even when my "actorsData" prop inside of "ActorsDetails.vue" lost it's data.
this.topActors = result;
});
},
methods: {},
};
</script>
ActorsList.vue
<template>
<div class="actors-list">
<router-link to="/">Home</router-link>
<div class="actors-list-container" v-if="allFiveActors">
<div
class="actor-container"
v-for="actorData in actorsData"
:key="actorData.id"
>
<router-link :to="'/actorslist/' + actorData.id">
<h3>{{ actorData.name }} | {{ actorData.id }}</h3>
</router-link>
</div>
</div>
</div>
</template>
<script>
export default {
name: "ActorsList",
props: ["actorsData"],
data() {
return {};
},
computed: {
allFiveActors() {
return this.actorsData.length > 0;
},
},
created() {
console.log(this.actorsData); <== Also tried to refresh the browser when I am on this page/component, prop data always exist.
},
};
ActorsDetails.vue (Page/Component that lost prop data)
<template>
<div class="actor-details">
<router-link to="/actorslist">Actors List</router-link>
<h1>Details page</h1>
<div class="actor-details-container" v-if="actorDetails">
<div class="actor-detail-info">
<h3>{{ actorDetails.name }}</h3>
<p>Birthday: {{ actorDetails.birthday }}</p>
</div>
</div>
</div>
</template>
<script>
import { getActorDetails } from "../util/TheMoveDatabase";
export default {
name: "ActorDetails",
props: ["actorsData", "actorId"],
data() {
return {
actorDetails: {},
};
},
methods: {
checkCurrentActorExist() {
const currentActor = this.getCurrentActor;
// console.log(currentActor);
if (!currentActor) {
// this.$router.push("/");
console.log("does not exist");
}
},
getActor() {
const currentActor = this.getCurrentActor;
console.log(currentActor);
console.log("RAN");
if (currentActor) {
getActorDetails(this.actorId).then((result) => {
this.actorDetails = result;
console.log(this.actorDetails);
});
}
},
},
created() {
this.checkCurrentActorExist();
this.getActor();
console.log(this.actorsData); <== When I am on this page/component and refresh the browser few times, sometimes my "actorsData" prop data is lost.
console.log(this.actorId);
},
computed: {
getCurrentActor() {
return this.actorsData.find(
(actor) => actor.id === parseInt(this.actorId)
);
},
},
};
</script>
Routes.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
Vue.use(VueRouter);
const routes = [
{
path: '/',
name: 'Home',
components: {
homePage: Home,
},
},
{
path: '/actorslist',
name: 'ActorsList',
component: () => import('../views/ActorsList.vue'),
},
{
path: '/actorslist/:actorId',
name: 'ActorDetails',
component: () => import('../views/ActorDetails.vue'),
props(route) {
// console.log(route);
return {
actorId: route.params.actorId,
};
},
},
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
});
export default router;
Just a guess, but maybe your loading-method sometimes takes to much time and the empty array already has been passed to the component.
I would try to clear the array and re-fill it with the loaded data instead of creating a new array (I would try to empty it using splice or pop and then refill it with push)

How to make nested routing in Vuejs?

HelloWorld.vue
import axios from "axios";
export const router = () => axios.get("https://fakestoreapi.com/products");
<template>
<div>
<div v-for="item in items" :key="item.id">
<b> id: {{ item.id }}</b>
<router-link
:to="`/${item.id}`"
>
{{ item.title }}
</router-link>
</div><!-- end v-for -->
<router-view></router-view>
</div>
</template>
<script>
import { router } from "./router";
export default {
name: "HelloWorld",
components: {},
data() {
return {
items: [],
};
},
mounted() {
router().then((r) => {
this.items = r.data;
});
},
};
</script>
User.vue
import axios from "axios";
export const routerid = (itemId) =>
axios.get("https://fakestoreapi.com/products/" + itemId);
<template>
<div>
<div v-if="item">
<h1>Price: {{ item.price }}</h1>
</div>
<tabs />
</div>
</template>
<script>
import { routerid } from "./routerid";
import tabs from "./tabs";
export default {
name: "User",
components: {
tabs,
},
data() {
return {
item: null,
};
},
mounted() {
this.loadData();
},
computed: {
routeId() {
return this.$route.params.id;
},
},
watch: {
routeId() {
console.log("Reload (route change)");
this.loadData();
}, //reload when route id changes
},
methods: {
loadData() {
console.log("Reloading, ID", this.routeId);
if (!this.routeId) return; // no ID, leave early
routerid(this.$route.params.id).then((item) => {
this.item = item.data;
});
},
},
};
</script>
tabs.vue
import axios from "axios";
export const tabsandcontent = async (itemId) =>
await axios.get("https://fakestoreapi.com/products?limit=" + itemId);
<template>
<div>
<div v-if="item">
<h1>description: {{ item.description }}</h1>
</div>
</div>
</template>
<script>
import { tabsandcontent } from "./tabsandcontent";
export default {
name: "User",
components: {},
data() {
return {
item: null,
};
},
mounted() {
this.loadData();
},
computed: {
tabsandcontent() {
return this.$route.params.id;
},
},
watch: {
tabsandcontent() {
console.log("Reload (route change)");
this.loadData();
}, //reload when route id changes
},
methods: {
loadData() {
console.log("Reloading, ID", this.tabsandcontent);
if (!this.tabsandcontent) return; // no ID, leave early
tabsandcontent(this.$route.params.id).then((item) => {
this.item = item.data;
});
},
},
};
</script>
main.js
import Vue from "vue";
import App from "./App.vue";
import VueRouter from "vue-router";
import HelloWorld from "./components/HelloWorld";
import User from "./components/User";
Vue.use(VueRouter);
const router = new VueRouter({
routes: [
{
path: "/HelloWorld",
name: "HelloWorld",
component: HelloWorld,
children: [{ path: ":id", name: "User", component: User }]
}
]
});
Vue.config.productionTip = false;
new Vue({
router,
render: (h) => h(App)
}).$mount("#app");
code:- https://codesandbox.io/s/combined-logic-api-forked-41lh0f?file=/src/main.js
can you please answer this, In main.js routing I changed from path: "/" to path: "/HelloWorld" then all of sudden output not reflecting... because in my project path:'/' indicates login page??? In this scenario what changes, i need to make, to make logic work
also where is the relation between path:'/' and api call??
You have same name for the variables in tabs component (In watch and computed). And In tabsandcontent.js, you have missed to fetch description for the specific item as performed in routerId.js.
Have a look at modified version which is working as you expected.
https://codesandbox.io/embed/combined-logic-api-forked-ji5oh4?fontsize=14&hidenavigation=1&theme=dark
First thing first, I want you to know that I don't understand what are you asking for. But I'm going to try to answer.
Your first question:
In main.js routing I changed from path: "/" to path: "/HelloWorld" then all of sudden output not reflecting.
Yes, you will not see your HelloWorld.vue component. You can see your page however if you type <your-url>/HelloWorld. Usually the / path is used for something like "Home" page.
However, I've tried checking out your codesandbox. And take a look at your HelloWorld.vue component.
I think you are confused because when you changed the path from / to /HelloWorld apart from the HelloWorld.vue not showing up. It somehow broken the link which causes the API in tabs.vue not functioning.
If that's the case, you just have to simply add HelloWorld/${item.id} in tabs.vue,
<template>
<div>
<div v-for="item in items" :key="item.id">
<b> id: {{ item.id }}</b>
<router-link
:to="`HelloWorld/${item.id}`" // --> Notice this line
>
{{ item.title }}
</router-link>
</div><!-- end v-for -->
<router-view></router-view>
</div>
</template>
This however, isn't a common thing to do routing. You should add your App URLs to main.js. Which also isn't common, but I'm assuming this is just a little reproduction code you made for StackOverflow.
Here are my CodeSandbox edits.
https://codesandbox.io/s/combined-logic-api-forked-jttt8p
I will update the answer again later, I'm still not on my personal laptop.

Vue.js - Dynamic component import in data and computed properties

I have component 'Page' that should display a component which is retrieved via its props.
I managed to get my component loads when I harcode my component path in my component data like this :
<template>
<div>
<div v-if="includeHeader">
<header>
<fv-header/>
</header>
</div>
<component :is="this.componentDisplayed" />
<div v-if="includeFooter">
<footer>
<fv-complete-footer/>
</footer>
</div>
</div>
</template>
<script>
import Header from '#/components/Header/Header';
import CompleteFooter from '#/components/CompleteFooter/CompleteFooter';
export default {
name: 'Page',
props: {
componentPath: String,
includeHeader: Boolean,
includeFooter: Boolean
},
data() {
componentDisplayed: function () {
const path = '#/components/my_component';
return import(path);
},
},
components: {
'fv-header': Header,
'fv-complete-footer': CompleteFooter,
},
}
</script>
But with the data I cannot refer to my props within my function as this is undefined.
I tried to used computed properties instead of data but I have the error "src lazy?0309:5 Uncaught (in promise) Error: Cannot find module '#/components/my_component'. But the module exists! But maybe not at that time ?
computed: {
componentDisplayed: function () {
const path = `#/components/${this.componentPath}`;
return import(path);
},
},
There must be away to deal with that but I am quite a beginner to vue.js :)
Instead of trying to import the component in your child component, instead import it in the parent component and pass the entire component as a prop.
<template>
<div :is="component" />
</template>
<script>
export default {
name: "page",
props: {
component: {
required: true
}
}
};
</script>
And in the parent
<page :component="component" />
and
import Page from './components/Page';
// and further down
data () {
return {
component: HelloWorld
}
}

Categories