Vue3 Components in a Separate File - vue.js

I have an app that I am porting from Vue2 to Vue3. I am not using a bundler as Vue is just providing simple interactivity on a page. This is the simplified version in Vue2:
// my-modal.js
var myModal = Vue.component('my-modal',
{
template:
`<div id="myModal">
<button #click.prevent="open=true">Open Modal</button>
<div v-if="open" class="my-modal">
<p>Hello from the modal!</p>
<button #click.prevent="open=false">Close</button>
</div>
</div>`,
data() {
return {
open: false
}
}
})
In Vue 2 this Works;
<script src="https://unpkg.com/vue#2"></script>
<div id="app">
<div class="outer">
<h3>Modal Example - {{ message }}</h3>
<div>
<my-modal />
</div>
</div>
</div>
<script src="/js/my-modal.js"></script>
<script>
const app = new Vue(
{
el: '#app',
data() {
return {
message: 'Hello Vue!'
}
}
});
</script>
For Vue3, per the documentation at: https://v3-migration.vuejs.org/breaking-changes/global-api.html#a-new-global-api-createapp I switched things over to what I expected would work:
<script src="https://unpkg.com/vue#3"></script>
<div id="app">
<div class="outer">
<h3>Modal Example - {{ message }}</h3>
<div>
<my-modal />
</div>
</div>
</div>
<script src="/js/my-modal.js"></script>
<script>
Vue.createApp({
data()
{
return {
message: 'Hello Vue!'
}
}
}).mount('#app')
</script>
and in the my-modal.js file I changed the first few lines to use the Global Vue:
const { createApp } = Vue;
const app = createApp({});
app.component('my-modal', ...
The Vue instance works but the component is not found with the error message: "Failed to resolve component: my-modal". I tried adding a 'components' section to the Vue instance and a few other things with no luck.
Any suggestions?

Each instance from createApp() is unique. That is, calling createApp() in index.html does not return the same instance from the previous call in my-modal.js.
One solution is to declare the global app instance before importing my-modal.js:
<!-- index.html -->
<script>
window._app = Vue.createApp({⋯})
</script>
<script src="/js/my-modal.js"></script>
<script>
// finally mount
window._app.mount('#app')
</script>
// js/my-modal.js
window._app.component('my-modal', {⋯})
demo

Related

vuejs not showing the value inside {{ }} , the text is displayed as it is

I developed a vuejs program and run the npx serve command. I go to the directory and run npx serve. I browse the http://localhost:300/myvuefile.html , I get the following output only.
{{count}} inside the button. My code :
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
<div id="app">
<button #click="count++">{{ count }}</button>
</div>
<script>
import { createApp } from 'vue'
const app = createApp({
data() {
return {
count: 0
}
}
})
app.mount('#app')
</script>
I have to get the value of the count and onclick the count should increment. Instead I get the output as {{count}} only. Please help to fix this issue.
According to the documentation-
When using the global build of Vue, all top-level APIs
are exposed as properties on the global Vue object.
So, either use like this-
const app = Vue.createApp({
data() {
return {
count: 0
}
}
})
app.mount('#app')
<div id="app">
<button #click="count++">{{ count }}</button>
</div>
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
Or use like this-
const { createApp } = Vue
const app = createApp({
data() {
return {
count: 0
}
}
})
app.mount('#app')
<div id="app">
<button #click="count++">{{ count }}</button>
</div>
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>

Vue 3 (CLI): Cannot read properties of undefined (reading 'get')

When switching to Vue 3 CLI and consequently refactoring the code, this.$http.get('/api/todo/') no longer works. Instead of being returned a list of todos from the database, I receive a Cannot read properties of undefined error in the console:
app.js:209 Uncaught TypeError: Cannot read properties of undefined (reading 'get')
at Proxy.getTodos (Todos.vue?4897:38:1)
at Proxy.mounted (Todos.vue?4897:28:1)
at eval (runtime-core.esm-bundler.js?d2dd:2722:1)
at callWithErrorHandling (runtime-core.esm-bundler.js?d2dd:155:1)
at callWithAsyncErrorHandling (runtime-core.esm-bundler.js?d2dd:164:1)
at hook.__weh.hook.__weh (runtime-core.esm-bundler.js?d2dd:2697:1)
at flushPostFlushCbs (runtime-core.esm-bundler.js?d2dd:341:1)
at render (runtime-core.esm-bundler.js?d2dd:6247:1)
at mount (runtime-core.esm-bundler.js?d2dd:4440:1)
at app.mount (runtime-dom.esm-bundler.js?2725:1574:1)
Additionally, I observe that both the apps and components lists are empty in Vue devtools.
After searching and experimenting with solutions for a few hours, I have not found a solution that works yet.
This is the current code causing the issues:
In Todos.vue, the template is rendered because I do se "Hi there", but I do not see any list items anymore:
<template>
<div id="TODOS">
Hi there
<ol>
<li v-for="todo in v_todos" :key="todo.id">
<span style="color:red;">{{ todo.name }}</span>
</li>
</ol>
</div>
</template>
<script>
export default {
// el: "#TODOS",
name: 'Todos',
data() {
return {
v_todos: [],
}
},
computed: {},
components: {},
mounted() {
this.getTodos();
},
methods: {
getTodos: function () {
this.$http.get('/api/todo/')
.then((response) => {
this.v_todos = response.data;
})
.catch((err) => {
console.log(err);
})
},
}
</script>
In App.vue:
<template>
<div id="App">
<Todos />
</div>
</template>
<script>
import Todos from './components/Todos.vue'
export default {
name: 'App',
components: {
Todos
}
}
</script>
In the HTML page todos.html:
...
<div id="App"></div>
...
In base.html, at the end of the body:
<script type="text/javascript" src="{% static 'src/vue/dist/js/chunk-vendors.js' %}"></script>
<script type="text/javascript" src="{% static 'src/vue/dist/js/app.js' %}"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-resource#1.3.5"></script>
I am completely new to Vue, so I would strongly appreciate if solution proposals are presented in a simple-to-understand way.
add to your main.js
import axios from 'axios';
const app = createApp(App);
app.config.globalProperties.$http = axios;

I get an error when try hello world in Vue

I got this error :
Component template should contain exactly one root element. If you are
using v-if on multiple elements, use v-else-if to chain them instead.
When try :
<template>
<h1>Il tuo oroscopo</h1>
<h3>{{ msg }}</h3>
</template>
<script>
export default {
data() {
return {
msg: 'Hello World!'
}
}
}
</script>
<style scoped></style>
You have to put a div in root. Only one.
<template>
<div>
<h1>Il tuo oroscopo</h1>
<h3>{{ msg }}</h3>
</div>
</template>
<script>
export default {
data() {
return {
msg: 'Hello World!'
}
}
}
</script>
<style scoped></style>
As error says itself Component template should contain exactly one root element.
This means, wrapped the template content with in a single element which will be work as a root element. Hence, wrapping with a <div> will resolve this error.
Demo :
Vue.component('child', {
props: ['childmsg'],
template: `<div><h1>Il tuo oroscopo</h1>
<h3>{{ childmsg }}</h3></div>`
});
var app = new Vue({
el: '#app',
data: {
msg: 'Hello World!'
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<child :childmsg="msg">
</child>
</div>

Message is Not displayed (vue.js 2)

ERROE 9:5 error 'Vue' is not defined no-undef
I added "import Vue from 'vue'" to the first line of the script. The error disappeared, but the message was not displayed.
Sorry for the rudimentary question.
views/About.vue
<template>
<div class="about">
<h1>This is an about page</h1>
<p>{{ message }}</p>
</div>
</template>
<script>
new Vue({
el: "#about",
data: {
message: "Hello Vue!",
},
});
</script>
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
<script>
export default {
data() {
return {
message: 'Hello !'
}
}
}
</script>
Just do like this.
From what I can see, you have already mounted your vue instance in your main.js, so there's no need to create another vue instance and mount it again in the About.vue file.
You only need the following lines of code in the About.vue file
In Vue 2
<template>
<div class="about">
<h1>This is an about page</h1>
<p>{{ message }}</p>
</div>
</template>
<script>
export default {
data: {
message: "Hello World!"
}
}
</script>
In Vue 3
In vue 3, the data property is now a method.
<template>
<div class="about">
<h1>This is an about page</h1>
<p>{{ message }}</p>
</div>
</template>
<script>
export default {
data() {
return {
message: "Hello World!"
}
}
}
</script>

vuejs 3 data options property no more reactive with external object

I have an app that shares an external module with other applications by sharing a global javascript object.
One of these apps is developed with vue 2 and when the global object is updated in the external module, the option data property of vue 2 is updated perfectly while in vue 3 it is not. I also tried with the new reactive property but nothing to do, is it a bug?
Not being able to make any changes to the external module because it is shared with other apps, how can I make it work in vue 3?
Here are some test links:
Vue 2 share external object
<script src="https://unpkg.com/vue"></script>
<script>
var EXTERNAL_OBJECT={
name:"Bob",
list:[{name:"Ivan"}]
}
function change_object(){
EXTERNAL_OBJECT.name+="+++"
EXTERNAL_OBJECT.list.push({name:"Carl"})
}
</script>
<button onClick="change_object()">change external object</button>
<div id="app">
<div>
{{share.name}}
</div>
<div v-for="item in share.list">
{{item.name}}
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
share:EXTERNAL_OBJECT
}
})
</script>
Vue 3 share external object
<script src="https://unpkg.com/vue#3.2.4/dist/vue.global.js"></script>
<script>
var EXTERNAL_OBJECT={
name:"Bob",
list:[{name:"Ivan"}]
}
function change_object(){
EXTERNAL_OBJECT.name+="+++"
EXTERNAL_OBJECT.list.push({name:"Carl"})
}
</script>
<button onClick="change_object()">change external object</button>
<div id="app">
<div>
{{share.name}}
</div>
<div v-for="item in share.list">
{{item.name}}
</div>
</div>
<script>
const app = Vue.createApp({
data () {
return {
share:EXTERNAL_OBJECT
}
}
});
app.mount('#app')
</script>
Vue 3 share external object with reactive property
<script src="https://unpkg.com/vue#3.2.4/dist/vue.global.js"></script>
<script>
var EXTERNAL_OBJECT={
name:"Bob",
list:[{name:"Ivan"}]
}
function change_object(){
EXTERNAL_OBJECT.name+="+++"
EXTERNAL_OBJECT.list.push({name:"Carl"})
}
</script>
<button onClick="change_object()">change external object</button>
<div id="app">
<div>
{{share.name}}
</div>
<div v-for="item in share.list">
{{item.name}}
</div>
</div>
<script>
const { createApp, reactive } = Vue
const app = createApp({
setup(){
let share = reactive(EXTERNAL_OBJECT)
return {
share
}
},
data () {
return {
msg:"reactive test"
}
}
});
app.mount('#app')
</script>
thanks
It is a bit hard to read ... I just look at the Vue3 Example.
How many file are you showing?
Cant write your EXTERNAL_OBJECT directly in the reactive property? Like:
const EXTERNAL_OBJECT = reactive({ name:"Bob",
list:[{name:"Ivan"}] });