link411 link412 link413 link414 link415 link416 link417 link418 link419 link420 link421 link422 link423 link424 link425 link426 link427 link428 link429 link430 link431 link432 link433 link434 link435 link436 link437 link438 link439 link440 link441 link442 link443 link444 link445 link446 link447 link448 link449 link450 link451 link452 link453 link454 link455 link456 link457 link458 link459 link460 link461 link462 link463 link464 link465 link466 link467 link468 link469 link470 link471 link472 link473 link474 link475 link476 link477 link478 link479 link480 link481 link482 link483 link484 link485 link486 link487 link488 link489 link490 link491 link492 link493 link494 link495 link496 link497 link498 link499 link500 link501 link502 link503 link504 link505 link506 link507 link508 link509 link510 link511 link512 link513 link514 link515 link516 link517 link518 link519 link520 link521 link522 link523 link524 link525 link526 link527 link528 link529 link530 link531 link532 link533 link534 link535 link536 link537 link538 link539 link540 link541 link542 link543 link544 link545 link546 link547

[Vue.js] How to upload cropped picture with vue-cropper.js?

So I’m using an npm package called vue-cropper.js to crop images and upload the cropped image to a remote server. However the uploading part of the cropped image is not working as all I’m getting is a CORS error. But the thing is, when I upload an image without cropping it, it works and there is no error. I don’t understand what I’m doing wrong.

I’ve checked the cropper.js docs numerous times and all they tell you to do is create a blob and append it to form data and then POST. Again, that’s what I’m doing.

Here is my template for the cropper component.

<vue-cropper
v-show=”imageSrc”
class=”vue-cropper”
ref=”cropper”
:guides=”true”
:view-mode=”1”
drag-mode=”crop”
:background=”true”
:rotatable=”true”
:aspect-ratio=”1”
:src=”imageSrc”
alt=”Image”
\></vue-cropper>

Here is my code for cropping and uploading.

crop() {
this.$refs.cropper
.getCroppedCanvas({
width: 200,
height: 200
})
.toBlob(blob => {
const formData = new FormData();
formData.append(“photo”, blob, ‘avatar’);
this.uploadImage(formData);
});
},
rotate() {
this.$refs.cropper.rotate(90);
},
uploadImage(formData) {
const token = getCookie(“ifragasatt_cookie”);
const url = “https://vem-user.fjardestatsmakten.se/userProfilePic";
const headers = {
“Content-Type”: “multipart/form-data”,
“Access-Control-Allow-Origin”: “*“,
“ifr-jwt-token”: token
};

axios.post(url, formData, { headers });
}
}

I expect to get an “ok” as a response from the endpoint. But I’m getting:

POST https://vem-user.fjardestatsmakten.se/userProfilePic 502

my-profile:1 Access to XMLHttpRequest at ‘https://vem-user.fjardestatsmakten.se/userProfilePic'
from origin ‘http://localhost:8080' has been blocked by CORS policy:
No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

Solution :

Does the back-end code had apply cors yet? Because I see Access-Control-Allow-Origin error in POST response. And did you convert image from base64 to blob?

Solution 2:

IT WORKS!!!! I had to add .png as to ‘avatar’.

[Vue.js] Vue error with Rangy library is not a function (but only inside hooks)

For a vue.js component, I use the Rangy library to highlight single words inside a text. This is working fine if Rangy is called from any method inside the methods object:

let applier = rangy.createClassApplier(‘some-class’);
applier.toggleRange(range);

But sometimes I need to restore a certain state on page load, so I tried using the same method inside the created and mounted hooks. This doesn’t work.

Right now, the first lines of the script in my component look like this:

import _ from ‘lodash’;
import rangy from ‘rangy’;
import ‘rangy/lib/rangy-classapplier’;

export default {

mounted: function() {
// Leave function if there is no data in DB to be restored
if (_.isEmpty(this.mostRecentAnswers))
return;

else {
// ERROR
let applier = rangy.createClassApplier(‘some-class’);
// …
}
}
// …
}

The error message is TypeError: rangy__WEBPACK_IMPORTED_MODULE_2___default.a.createClassApplier is not a function at VueComponent.mounted

I use vue.js with Laravel and Laravel Mix (which is a wrapper for Webpack).

What’s wrong with my code? Note I also import Lodash and use it inside the hook without any errors.

Solution :

I would recommend making a vue.js plugin out of this to make it easier:

// plugins/vue-rangy.js

import rangy from ‘rangy’

const VueRangy = {
install (Vue, options) {
if (options.hasOwnProperty(‘init’) && options.init) {
rangy.init()
}

Vue.prototype.$rangy = rangy
}
}

export default VueRangy

Then use it like any other plugin:

import VueRangy from ‘plugins/vue-rangy’

Vue.use(VueRangy, {
init: true
})

Then just use this.$rangy in the components.

Solution 2:

I had to use rangy.init() which initializes Rangy if it has not already been initialized:
https://github.com/timdown/rangy/wiki/Rangy-Object#rangyinit

[Vue.js] How to reference static assets within vue javascriptUsing from within JavaScript require()Use relative path

I’m looking for the right url to reference static assets, like images within vue.js javascript.

For example, I’m creating a leaflet marker using a custom icon image, and I’ve tried several urls, but they all return a 404 (Not Found):

Main.vue:

var icon = L.icon({
iconUrl: ‘./assets/img.png’,
iconSize: [25, 25],
iconAnchor: [12, 12]
});

I’ve tried putting the images in the assets folder and the static folder with no luck. Do there is to tell vue.js to load those images somehow?

Solution :

For anyone looking to refer images from template, You can refer images directly using ‘@’

Example:

<img src=”@/assets/images/home.png”/>

Solution 2:

In a vue.js regular setup, /assets is not served.

The images become src=”data:image/png;base64,iVBORw0K…YII=” strings, instead.

Using from within JavaScript: require()

To get the images from JS code, use require(‘../assets.myImage.png’). The path must be relative (see below).

So the code would be:

var icon = L.icon({
iconUrl: require(‘./assets/img.png’), // was iconUrl: ‘./assets/img.png’,
// …
});

Use relative path

For example, say you have the following folder structure:

- src
+- assets
- myImage.png
+- components
- MyComponent.vue

If you want to reference the image in MyComponent.vue, the path sould be ../assets/myImage.png

Here’s a DEMO CODESANDBOX showing it in action.

Solution 3:

In order for Webpack to return the correct asset paths, you need to use require(‘./relative/path/to/file.jpg’), which will get processed by file-loader and returns the resolved URL.

computed: {
iconUrl () {
return require(‘./assets/img.png’)
// The path could be ‘../assets/img.png’, etc., which depends on where the vue.js file is
}
}

See VueJS templates - Handling Static Assets

Solution 4:

Right after oppening script tag just add import someImage from ‘../assets/someImage.png’
and use it for an icon url iconUrl: someImage

Solution 5:

What system are you using? Webpack? Vue-loader?

I’ll only brainstorming here…

Because .png is not a JavaScript file, you will need to configure Webpack to use file-loader or url-loader to handle them. The project scaffolded with vue-cli has also configured this for you.

You can take a look at webpack.conf.js in order to see if it’s well configured like


{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: ‘url-loader’,
options: {
limit: 10000,
name: utils.assetsPath(‘img/[name].[hash:7].[ext]‘)
}
},

/assets is for files that are handles by webpack during bundling - for that, they have to be referenced somewhere in the javascript code.

Other assets can be put in /static, the content of this folder will be copied to /dist later as-is.

I recommend you to try to change:

iconUrl: ‘./assets/img.png’

to

iconUrl: ‘./dist/img.png’

You can read the official documentation here: https://vue-loader.vuejs.org/en/configurations/asset-url.html

Hope it helps to you!

[Vue.js] pass parameter in URL using vuejs and laravel

I wanna display data with specefic ID in laravel using vuejs.
I get the ID from the link but it seems that there is no request sent to the controller.
api.php :

<?php

use Illuminate\Http\Request;

Route::middleware(‘auth:api’)->get(‘/user’, function (Request $request) {
return $request->user();
});

Route::resource(‘user’,’API\UserController’);
Route::resource(‘departement’,’API\DepartementController’);
Route::resource(‘specialite’,’API\SpecialiteController’)->parameters([‘specialite’=>’id’]);

my controller :

public function show($id)
{
$specialite=Specialite::with(‘dep’)->findOrFail($id);
$spec = Specialite::with(‘dep’)->where(‘id’,$specialite)->get();
return $spec;
}

my view :

<script>
export default {

data(){
return{
specialites:{},
form: new Form({
id:’’,
name:’’,
user_id:’’,
bio:’’
}),
id:0,
}

},

methods: {
loadspecialite(){
//axios.get(‘api/user’).then(({data})=>(this.enseignants=data.data));
axios.get(‘api/specialite/‘+this.id).then(response=>{this.specialites=response.data;});
},
created() {
this.id=this.$route.params.id;
this.loadspecialite();
Fire.$on(‘AfterCreate’,()=>{
this.loadspecialite();

})

}
}
</script>

Vue-router:

let routes = [
{ path: ‘/Profile/:id’, component: require(‘./components/a.vue’).default },
]

thank you.
hope tou will help me.

Solution :

Firstly, I don’t see how this.id would carry the id from the router as created is not guaranteed to have been fired AFTER the router has routed.

the loadspecialite should get the value from the currentRoute when called and i think the var is slightly wrong:

let id = this.$router.currentRoute.params.id;

the route resource should be:

Route::resource(‘specialite’,’API\SpecialiteController’);

The request uri would be:

axios.get(`/api/specialite/${id}`).then(…)

You can find out the exact uri path for all registered routes in Laravel by using an SSH terminal to run console command: php artisan route:list

This should produce the following:

+——–+———–+———————————-+————————+————————————————————————+————–+
| Domain | Method | URI | Name | Action | Middleware |
+——–+———–+———————————-+————————+————————————————————————+————–+
| | GET|HEAD | api/specialite | api.specialite.index | App\Http\Controllers\API\ApplicationController@index | api,auth:api |
| | POST | api/specialite | api.specialite.store | App\Http\Controllers\API\ApplicationController@store | api,auth:api |
| | GET|HEAD | api/specialite/create | api.specialite.create | App\Http\Controllers\API\ApplicationController@create | api,auth:api |
| | GET|HEAD | api/specialite/{specialite} | api.specialite.show | App\Http\Controllers\API\ApplicationController@show | api,auth:api |
| | PUT|PATCH | api/specialite/{specialite} | api.specialite.update | App\Http\Controllers\API\ApplicationController@update | api,auth:api |
| | DELETE | api/specialite/{specialite} | api.specialite.destroy | App\Http\Controllers\API\ApplicationController@destroy | api,auth:api |
| | GET|HEAD | api/specialite/{specialite}/edit | api.specialite.edit | App\Http\Controllers\API\ApplicationController@edit | api,auth:api |

P.S. there is no need to create a form object if you are not sending any attached files, Laravel and axios will revert to use JSON by default with ajax requests.

Laravel will return JSON object by default in response to a JSON ajax call direct from a resource on the controller:

function show($id) {

return Specialite::findOrFail($id);

}

Fail will return a 400+ header that in turn can be handled by axsios .catch

.catch( error => { console.log(error.response.message) } )

Laravel from validation messages would be accessible via:

.catch( error => { console.log(error.response.data.errors) } )

Axios will post an object/array as a JSON request:

data() {

return {

form: {
id:’’,
name:’’,
user_id:’’,
bio:’’
},

}
}

axios.post(‘/api/specialite’,this.form).then(…);

Solution 2:

I do believe that the code is functioning fine. It is a formatting error in the vue.js component object. Basically the created() handler is in the due methods, thus it won’t be handled when the created event is done.

// the code snippet where there is an issue
methods: {
loadspecialite(){
//axios.get(‘api/user’).then(({data})=>(this.enseignants=data.data));
axios.get(‘api/specialite/‘+this.id).then(response=>{this.specialites=response.data;});
}, // end of loadspecialite
created() {
this.id=this.$route.params.id;
this.loadspecialite();
Fire.$on(‘AfterCreate’,()=>{
this.loadspecialite();

})

} // end of created
} //end of methods

What you should do is just remove the created() out of methods and also check the syntax of the function again.

const Foo = {
template: ‘<div>foo</div>’
}
const Bar = {
template: ‘<div><span> got {form}</span></div>’,
data() {
return {
specialites: {},
form: ‘fetching…’,
id: 0,
}

},

methods: {
loadspecialite() {
// test method for getting some data
axios.get(‘https://httpbin.org/anything/' + this.id)
.then(response => {
this.form = response.data.url;
}).catch(error => {
console.error(error)
})
},
}, // <- this is the end of methods {}

/**
* Created method outside of methods scope
*/
created() {
this.id = this.$route.params.id;
this.loadspecialite();
}
}

// rest is vues demo router stuff
const routes = [{
path: ‘/foo’,
component: Foo
},
{
path: ‘/bar/:id’,
component: Bar
}
]
const router = new VueRouter({
routes // short for `routes: 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>vue.js Routed</title>
<script src=”https://unpkg.com/vue/dist/vue.js"></script>
<script src=”https://unpkg.com/vue-router/dist/vue-router.js"></script>
<script src=”https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<style>
button {
padding: 0.75rem;
background: #eee;
border: 1px solid #eaeaea;
cursor: pointer;
color: #000
}

button:active {
color: #000;
box-shadow: 0px 2px 6px rgba(0,0,0,0.1);
}

</style>
</head>

<body>

<div id=”app”>
<h1>Hello App!</h1>
<p>
<span> Click a button </span>
<router-link to=”/foo”><button>Go to Foo</button></router-link>
<router-link to=”/bar/3”><button>Go to Where it will get the data</button></router-link>
</p>
<!– route outlet –>
<!– component matched by the route will render here –>
<router-view></router-view>
</div>

</body>

</html>

Solution 3:

All thing has set well, just the show method should respond in JSON:

use Illuminate\Http\Response;

function show($id) {
result = Specialite::findOrFail($id);
return response()->json($result,Response::HTTP_OK);
}

[Vue.js] bootstrap-vue <b-pagination> component not changing pages on click

to implement a pagination component b-pagination w/bootstrap-vue.js but it will only display page one. when following the setup in documentation but they only show an example using a table not an unordered list. there is :

<template>
<div class=”results overflow-auto” v-cloak>
<h3>Search Results</h3>

<modal v-if=”showModal” @close=”showModal = false”>
<!–
you can use custom content here to overwrite
default content
-->
<template v-slot:header>
<h1>NASA Image</h1>
</template>

<template v-slot:body>
<b-img class=”modal-image” v-bind:src=”attribute”></b-img>
</template>
</modal>

<!– ======== Pagination Markup ============ –>
<b-pagination
v-model=”currentPage”
:total-rows=”rows”
:per-page=”perPage”
:items=”items”
aria-controls=”my-list”
\></b-pagination>

<p class=”mt-3”>Current Page: { currentPage }</p>

<!– ==========End Pagination Markup ======== –>

<!– Limit output to 100 items –>

<ul
class=”search-results”
id=”my-list”

\>
<li v-for=”(item, index) in propsResults.items.slice(0,100)” :key=”index”>
{ item.data[0].title}
<span>
<b-img
thumbnail
class=”thumbnail”
:src=”item.links[0].href”
alt=”Fluid image”
id=”show-modal”
v-on:click=”imageModal”
\></b-img>
</span>
</li>
</ul>
</div>
</template>

and my javascript is :

export default {
name: “SearchResults”,
props: [“propsResults”],
data() {
return {
showModal: false,
attribute: “”,
perPage: 10,
currentPage: 1,
items: this.$props.propsResults.items
};
},
computed: {
rows() {
return this.$props.propsResults.items.length;
}
}

The pagination component is displaying all 100 items of items array on one page. I should also note I do not see the items array in the b-pagination props object per vue.js dev tools in FF. is this normal? Any insight appreciated..

Solution :

You should still be using currentPage to choose which items to show. The b-pagination component only changes that number.

Try using this line:

<li v-for=”(item, index) in items.slice(10*(currentPage-1),10*(currentPage))” :key=”index”>

[Vue.js] how can i use adonis js and nuxt and electron and local database like mongoDB or Sqlite?

to create an app, that can run for desktop
and I will use nuxtjs and adonis.

My issue is how can I add electron js to it and use local Database like sqlite in it
because when I create nuxt adonis app I cannot how can I add electron
to it and actually how can I handle my database in this desktop app

Solution :

assuming that the other queries are solved after reading comments.. so explaining only mongodb part…

using some common variable & function names used widely in community to illustrate example…

like mainWindow or cerateWindow…

if you want to run mongodb from electron you can use child_process.execFile to spawn non-blocking process from electron..

you can run before or after of createWindow..

for before run it directly from main process and use stdout and stderr of child_process for possible outcomes…

and if you wants to run it after createWindow the send signal to run it from mainWindow through ipcRenderer or whatever you are comfortable with…

code example -

const { execFile } = require(‘child_process’)

let mongoDbCP = execFile(‘path_to_mongod_file, [‘–dabpath=path_to_db’, ‘any_other_args], { ‘any_options’: ‘if_you_want_to_pass_for_child_process’ }, (error) => { \* handle error *\ })

mongoDbCP.stdout.on(‘data’, (data) => {
console.log(`stdout: ${data}`);
});

if you are on windows then whenever you quit the app mongod will exit too…
but on macos you need to terminate manually before quitting with killall [process_name] or kill -9 [process_pid] explicitly ..

[Vue.js] How to bind method to an elements click in v-for cycle?

Iv got a v-for, and i need every element in this cycle to react on mouseclick. When i bind a method like i usually do, nothing happens. But outside the v-for this method i use seems to be working as expected.
What do i do wrong?

Here is the html code

<div v-for=”day of days” v-on:click=”dayClick(day.id)”>
{ day.day }
</div>

This is vue.js app code

var app = new Vue({
el: ‘#app’,
data: {
days: [],
},
methods: {
dayClick: function (dayId) {
console.log(dayId);
}
}
})

When i bind this method to any other element outside the v-for, it works fine

Im getting days[] in mounted like this

axios({
method: ‘get’,
url: ‘{URL::to(‘api/calendar/days’)}?token=’ + this.user.token + ‘&userId=’ + this.user.id
}).then((response) => {
this.days = response.data.days;
this.daysOfWeek = response.data.daysOfWeek;
})```

Solution :

And if you do something like this?

<template v-for=”(day) in days”>
<div v-on:click=”dayClick(day.id)”>
{ day.day }
</div>
</template>

Solution 2:

As it always appears - im my own worst enemy. I had pointer-events: none; for element i was trying to look at. Sry guys, and thank you for help. Im much more stupid than all of you

[Vue.js] how to filter laravel api pagination with vuejs

Ok so when using Laravel’s pagination for api resource and it gives me the structure like below :

{
current_page: 1,
data: [
{
some data
},
{
somedata
}
],
first_page_url: “http://localhost:8000/api/accommodation?page=1",
from: 1,
last_page: 3,
last_page_url: “http://localhost:8000/api/accommodation?page=3",
next_page_url: “http://localhost:8000/api/accommodation?page=2",
path: “http://localhost:8000/api/accommodation",
per_page: 2,
prev_page_url: null,
to: 2,
total: 5
}

Now if to write a filter for my api to search something in it and to search in all api not just the first page how can do it? Should I store all in vuejs or react then filter or is there any way to read all the data or even I should not use the laravel pagination for it as it may cause trouble for frontend?

Solution :

When you paginate with laravel, it takes all the parameters present in the request. So you have to make this kind of request :

http://localhost:8000/api/accommodation?page=1&filter1=blabla&filter2=blabla

Then the application will receive the result like this :

{
current_page: 1,
data: [
{
some data
},
{
somedata
}
],
first_page_url: “http://localhost:8000/api/accommodation?page=1&filter1=blabla&filter2=blabla",
from: 1,
last_page: 3,
last_page_url: “http://localhost:8000/api/accommodation?page=3&filter1=blabla&filter2=blabla",
next_page_url: “http://localhost:8000/api/accommodation?page=2&filter1=blabla&filter2=babla",
path: “http://localhost:8000/api/accommodation",
per_page: 2,
prev_page_url: null,
to: 2,
total: 5
}

BUT, in my opinion, the pagination must be done if you have a lot of rows in the database. If it is not the case, I prefer to make an unique call to my api , which get all the rows, and then filter dynamically on the front side (with js filter for example). Let say about 100 rows…. (but it can also depend of other parameters).

Is it more clear for you ?

[Vue.js] Axios Request - Gzip data from PHP API

is it possible to gzcompress data in PHP and then have Axios request it?

I’ve tried doing this but keep getting this error: “Malformed UTF-8 characters, possibly incorrectly encoded.”

My Axios request looks like this:

axios({
method: ‘get’,
url: ‘https://someapi.com/api/test',
data: { },
config: { headers: { ‘Content-Type’: ‘application/json’, ‘Accept-Encoding’: ‘gzip’ }
})
.then(response => {
response.data.forEach(el => {
this.transactions.push(JSON.parse(el));
this.transactionsFull = this.transactions;
});
this.loading = false;
console.log(this.transactions);
})
.catch(e => {
this.errors.push(e)
})

$result = openssl_decrypt($cipher_text, ‘aes-256-gcm’, $key, OPENSSL_RAW_DATA, $iv, $auth_tag);

$json = json_decode($result);
$channel = Channel::where(‘uuid’, $json->payload->authentication->entityId)->first();
$gzencode = gzencode(json_encode(array(‘transaction’ => $json, ‘relation’ => json_decode($channel))), 8);

Redis::lpush(‘transactions_gzencode’, $gzencode);

$length = 0;
$transactions = Redis::lrange(‘transactions_gzencode’, 0, -1);
foreach($transactions as $item) {
$length += strlen($item);
}
header(‘Content-Encoding: gzip’);
header(‘Content-Type: application/json’);
header(‘Content-Length: ‘ . $length);
return $transactions;

Solution :

I believe that axios is not able to decompress gzip, but the browser should be able to do it before axios even touches the response. But for the browser to do so you must respond with the proper http header and format.

Note that to use the compressed data in the http response body you must use gzencode, not gzcompress, according to php documentation.

Example PHP:

$compressed = gzencode(json_encode([‘test’ => 123]));
header(‘Content-Type: application/json’);
header(‘Content-Encoding: gzip’);
header(‘Content-Length: ‘ . strlen($compressed));
echo $compressed;

Example JS:

console.log(await (await fetch(‘/test’)).json());
// {test: 123}

Edit

Since what you are trying to do is to send an array of individually compressed items, you can output the data in a JSON encoded array of base64 encoded binary compressed data.

Example of how to use pako.js to decompress the array of compressed transactions returned from the server:

PHP:

$transactions = [‘first’, ‘second’, ‘third’];
echo json_encode(array_map(‘base64_encode’, array_map(‘gzencode’, $transactions)));

JS:

(async () => {
const transactions = (await (await fetch(‘/test’)).json())
.map(atob)
.map(blob => pako.inflate(blob, { to: ‘string’ }));

console.log(transactions);
})();

Notice that now I didn’t include the headers, cause when just sending a regular json encoded array.

The downside of this approach is that there won’t be much benefit on compressing the data, since it is being converted to base64 before sending to the client. It is necessary to encode as base64, because otherwise json_encode would try to handle the binary data as string and it would lead to string encoding errors.

You can still compress the resulting json encoded string before sending to the client like was done I the previous answer, but I’m not sure if the compression would still be good enough:

$compressedTransactions = array_map(‘gzencode’, [‘first’, ‘second’, ‘third’]);

$compressed = gzencode(json_encode(array_map(‘base64_encode’, $compressedTransactions)));
header(‘Content-Type: application/json’);
header(‘Content-Encoding: gzip’);
header(‘Content-Length: ‘ . strlen($compressed));
echo $compressed;

[Vue.js] VueJS Cannot render component inside component

there is really basic vue.js app (on Rails):

hello_vue.js:

import vue.js from ‘vue/dist/vue.esm’
import TurbolinksAdapter from ‘vue-turbolinks’
Vue.use(TurbolinksAdapter)

import CollectionSet from ‘../collection_set.vue’

document.addEventListener(‘turbolinks:load’, () => {
const app = new Vue({
el: ‘#app’,
components: { CollectionSet }
})
})

collection_set.vue:

<script>
import Collectable from ‘./collectable.vue’
export default {
components: { Collectable }
}
</script>

<template>
<p>test</p>
<collectable />
</template>

collectable.vue:

<script>
export default {
name: ‘collectable’
}
</script>
<template>
<p>test 2</p>
</template>

my webpage:

<div id=”app”><collection-set /></div>

With above example I don’t see anything, but when I remove <collectable /> from collection_set.vue, I see test. I don’t have any errors.

Why collectable is not being rendered?

Solution :

Change the template code of collection_set.vue.js to

<template>
<div>
<p>test</p>
<collectable />
</div>
</template>

the reason for error is that Component template should contain exactly one root element
Here we were trying to craete two root elements p and collectable

Now that I wrapped it within a parent div container, it works just fine.
Please try and let me know if it helps.

One suggestion is that always check into console of browser devtools to check what could be the issue. In this case, the console gave the exact error, also the code compilation failed with same error.

Solution 2:

In Vue, each component must have only ONE root element, meaning you need to have a tag like or and inside it all the template.