Vue js keep returning "Unknown custom element" - vue.js

I'm sure i didn't type anything wrong in my code, because i didn't even change it, but i just keep getting Unknown custom element error in console, here is my code:
app.js
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
window.Vue = require('vue');
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
Vue.component('example-component', require('./components/ExampleComponent.vue'));
const app = new Vue({
el: "#app"
});
ExampleComponent.vue
<template>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card card-default">
<div class="card-header">Example Component</div>
<div class="card-body">
I'm an example component.
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>

Main File
require('./bootstrap');
window.Vue = require('vue');
<template>
<example-component></example-component>
</template>
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
Vue.component('example-component', require('./components/ExampleComponent.vue'));
const app = new Vue({
el: "#app"
});
<template>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card card-default">
<div class="card-header">Example Component</div>
<div class="card-body">
I'm an example component.
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>

Related

why is codemirror turning up readonly under vue

If I have the following code, code mirror comes up readonly
<div class="container">
<div class="row">
<div class="col-md-2">
<textarea id="code"><h1>hi</h1></textarea>
</div>
</div>
</div>
<script>
var vue = new Vue(
{
el : ".container",
created() {this.editor = CodeMirror.fromTextArea(document.getElementById('code'), {lineNumbers: true, mode:"htmlmixed"});}
})
</script>
if I change "container" to "container1" so that the vue element doesn't match - it's editable.
How do I fix it?

Passing props to vue instance from .blade.php file using createElement and render function

EDIT: Some more information:
I have a main-page.blade.php file, with this:
//main-page.blade.php where vue instance will mount
<div id="main-page" class=" bg-uoi-green">
<main-page :data=['one'] ></main-page>
</div>
There is also a main.js file importing the app.js file of Vue, where the instance for main-page is defined ( I have installed vue-loader and template compiler).
The app.js for Vue is:
//app.js of Vue
import Vue from 'vue'
import './assets/tailwind.css'
//
// import MainPage from './components/MainPage.vue'
// const mainpage_inst=new Vue({
// el: '#main-page',
// components: {
// MainPage,
// },
// props: ['data'],
// });
Vue.config.productionTip = false
export default {
mainpage_inst,
}
Compiling for my application was giving me exactly what was needed. But then, if I try to also check the Vue directory using vue client, I get an empty page; this was to be expected since the vue-cli does not use the full-build. But even when I changed
// import Vue from 'vue'
to
import Vue from 'vue/dist/vue.js';
I was getting a blank page when visiting localhost:8080 from vue-cli.
I was able to fix it by using the render function of vue. So now, the instance became:
import MainPage from './components/MainPage.vue'
// Main page instance
const mainpage_inst = new Vue({
render: h => h(MainPage),
}).$mount('#main-page')
But, no matter how I try to pass props as before, my main application cannot see them, in contrast to the previous writing where it was able, but vue-cli was producing a blank page.
For clarification: I have a Vue-app inside a different app that is loaded with all the required( I think) modules to read and compile .vue files. But I would also like to be able to run the Vue-app using the vue-cli.
So, is my main-app missing a module and is not able to get the props? Or is there some other way to make 'understand'?
Thanks again.
In the past, I was using the following code to create the application instance :
// const mainpage_inst=new Vue({
// el: '#main-page',
// components: {
// MainPage,
// },
// props: ['data'],
// });
and I was calling the MainPage component from a .blade.php file by passing the props:
<main-page :data=" {{ $data_to_send_as_props }}" > </main-page>
Now I want to use the following code:
import MainPage from './components/MainPage.vue'
// Main page instance
const mainpage_inst = new Vue({
render: h => h(MainPage),
}).$mount('#main-page')
but if I try to define the props as before, the application does not recognizes them. What is the correct way to write the above excerpt of code, so that props will be passed ? In other words, how and were should I add the props definition on the instance above (note also that I should implement also the change mentioned in the answer of Daniel)
Edit:
This is a simplified version of the MainPage.vue component
<template>
<div class=" h-screen w-screen md:text-2xl text:2xl " id="main-page ">
<div class=" flex flex-shrink text-4xl md:text-9xl font-bold md:ml-20 md:my-5 md:py-0 py-10 title">
A Title
</div>
<div class="flex flex-col flex-grow h-1/3 ">
<div v-for="(item,index) in slicedArray " v-bind:key="item.id" >
<div class=" flex flex-col md:flex-row md:flex-grow w-full hover:bg-uoi-green px-10 border-black border-2 transition duration-500 cursor-pointer ease-in-out bg-opacity-70 transform hover:bg-opacity-95" :class="{active: isActive === item.id}">
<div class=" date-font h-full w-1/6 md:flex-grow px-2 py-4"> {{item.date}} — </div>
<div class=" h-full w-2/3 md:flex-grow px-2 py-4 text-left"> {{item.title}} </div>
<div class=" date-font h-full w-1/6 md:flex-grow px-2 py-4 text-right"> {{item.exp_date}} </div>
</div>
<div class=" bg-white py-10 px-20" v-if="isActive === item.id">
<div > {{item.text}} </div>
<div class='file'> <a href=''> Σχετικό αρχείο </a>
<!-- <img src="../assets/curved-up-arrow-.png" class="arrow"/> -->
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name:'MainPage',
props: ['data'],
data(){
return{
isActive: null,
newsToShow: 3,
totalnews: 0,
array:[],
slicedArray:[],
}
},
mounted(){
this.newsToShow=3;
this.array=this.data;
this.totalnews = this.array.length;
// console.log(this.array)
this.slicedArray=this.array.slice(0,this.newsToShow)
},
}
</script>
<style scoped>
</style>
One of the breaking changes in Vue 3 was that the Global Vue API was changed to use an application instance. To create a vue app, use the createApp function to create the instance.
a-new-global-api-createapp
The render function (h) is not provided by the render function, so you need to import it. docs
so your instantiation should look something like this:
import { h, createApp } from 'vue'
import MainPage from './components/MainPage.vue'
// Main page instance
const mainpage_inst = new createApp({
render: () => h(MainPage),
}).$mount('#main-page')

VueJS Modal component inside component

I have a component like this:
<test></test>
I declare this as follows:
Vue.component('test', {
data: {
showModal: true
},
methods: {
displayComponentModalDialog: function() {
this.showModal = true;
}
},
template: `<button #click='displayComponentModalDialog'>test</button>`
});
The <test></test> component is then placed somewhere inside the <div id="#app"> wrapper.
var app = new Vue({
router,
el: '#app',
// etc.
})
Now, I want to display another component inside the test component. So in this case I want a dialog to appear after I click the button in test component. I am not able to achieve this.
What I did is adding a new component:
Vue.component('dialog', {
template: '#dialog-template'
});
And then the following code, although I do not know for sure where to put it.
<!-- template for the modal component -->
<script type="text/x-template" id="dialog-template">
<transition name="dialog">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
default header
</slot>
</div>
<div class="modal-body">
<slot name="body">
default body
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
<button class="btn btn-primary" #click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
<!-- use the modal component, pass in the prop -->
<dialog v-if="showModal" #close="showModal = false">
<h3 slot="header">header</h3>
<p slot="body">
test
</p>
</dialog>
I tried putting this code inside the <test></test> but doesn't work. If I put it inside the template attribute in the component structure, it complains about only one root element.
So it is clear I miss some basic conception how this actually works in VueJS. Someone can help me clarify? Thanks.
As far as I can see your component indeed doesn't have a root tag. Templates have to have a root tag.
This is NOT a valid Vue template:
<div>
<h1>Stuff</h1>
</div>
<h2>Other stuff</h2>
This IS a valid Vue template:
<div>
<div>
<h1>Stuff</h1>
</div>
<h2>Other stuff</h2>
</div>
Note that in the second version we have a single root element for the template, a <div>, whereas in the first one we do not.
You have both a <script></script> and a <dialog></dialog> in your component template.
if you want to add another component in your test component . you can use slot on it.
You can refer to this documentation: https://v2.vuejs.org/v2/guide/components-slots.html
Example:
//component 1
<template>
<div id="modal">
// do something for your modal here.
<slot></slot> // reserve area for your another html or component.
</div>
</template>
// component 2
<template>
<your-modal-component>
<another-component>
</your-modal-component>
</template>

Laravel 5.4 Vue Declarative Rendering

In a laravel 5.4 environment I want to render the text "Example" in the .panel-heading of Example.vue. After doing npm run watch I get the following Vue warn:
'Property or method "message" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.'
app.js
require('./bootstrap');
window.Vue = require('vue');
Vue.component('example', require('./components/Example.vue'));
const app = new Vue({
el: '#app',
data: {
message: 'Example'
}
});
Example.vue
<template>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading" >{{ message }}</div>
<div class="panel-body">
I'm an example component!
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>
app.blade.php
<html>
<!-- ... -->
<body>
<div id="app">
<example></example>
</div>
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
Your Example.vue component doesn't have access to its parent's properties. You need to define message within the same scope of the component you are trying to use it in.
You can do this by adding message as a data property in your Example component:
// Example.vue script
export default {
data() {
return {
message: 'Example',
}
},
}
Or you can pass it in as a prop:
// Example.vue script
export default {
props: ['message'],
}
In your case, you would pass a value for the message prop like this:
// in app.blade.php
<example message="Example"></example>
Here's the documentation on Vue Component props.

Vue JS Component reattach or Cache

VueJS component doesn't get cached or atleast reattached after navigation. On refresh or launch everything gets attached and rendered well but after navigating to another page then back. The First Component - Carousel - component in my case doesn't get rendered but the API call is made.
<template>
<div class="rel">
<div id="homeCarousel" class="owl-carousel owl-slider">
<div class="item" v-for="product in featured">
<div class="bg-holder top-area-half" >
<div class="bg-mask-lighten"></div>
<img class="bg-img" v-bind:src="product.feature_image_url">
<div class="hero-caption">
<div class="container">
<h3 class="hero-title">{{product.feature_title}}</h3>
<p class="hero-subtitle">{{product.feature_subtitle}}</p>
<a class="btn btn-white btn-ghost btn-lg hero-btn" href="#">Shop now</a>
</div>
</div>
</div>
</div>
</div>
<div id="hero-slider-nav" class="hero-slider-nav">
<div class="container">
<div class="pull-right"></div>
</div>
</div>
</div>
</template>
<style>
</style>
<script>
export default{
data(){
return{
featured:[]
}
},
ready(){
},
mounted(){
this.getFeaturedProducts();
},
components:{
},
methods: {
getFeaturedProducts: function () {
Vue.http.get('/api/product/filter/featured=1').then(
(response) => {
this.featured = response.body;
}
)
}
}
}
</script>
`
<template>
<div class="global-wrapper clearfix ">
<keep-alive>
<Carousel></Carousel>
</keep-alive>
//The rest of the code which is just importing the Component
I found out what i was doing wrong. I had a separate JS/JQuery file and on the document ready i was initializing an owl carousel by id #('homeCarousel').owlCarousel({}) . What worked was, since i had already bootstrapped owl carousel -> on the mounted lifecycle callback i was now targeting the element and making it an owl carousel.