I installed Vue via npm and wanted to use it. Now when I load my page I get an error:
Uncaught SyntaxError: Unexpected token import in main.js:1
It worked when I put it the link to vue CDN in my HTML code, but now that I installed via NPM I receive this error.
Update
I find it strange that it does not work with any import at all. Even my custom components. As soon as I use the import statement, I get this error.
The Vue File:
import Vue from 'vue';
import axios from 'axios';
import Form from './core/Form';
window.Vue = Vue;
window.axios = axios;
window.Form = Form;
window.Event = new class {
constructor() {
this.vue = new Vue();
}
fire(event, data = null) {
this.vue.$emit(event, data);
}
listen(event, callback) {
this.vue.$on(event, callback);
}
};
Vue.component('panel', {
template: `
<div :class="panelType">
<div class="panel-heading">
<slot name="header"></slot>
</div>
<div class="panel-body">
<slot></slot>
</div>
</div>
`,
props: {
name: { required: true }
},
computed: {
panelType: function() {
switch(this.name) {
case 'default': return 'panel panel-default';
case 'primary': return 'panel panel-primary';
}
}
}
});
Vue.component('tabs', {
template: `
<div>
<div class="tabs-container">
<ul class="nav nav-tabs">
<li v-for="tab in tabs" :class="{'tab-pane active': tab.isActive }">
<a :href="tab.href" #click="selectTab(tab)">{{ tab.name }}</a>
</li>
</ul>
<div class="tab-content">
<slot></slot>
</div>
</div>
`,
data() {
return { tabs: [] };
},
created() {
this.tabs = this.$children;
},
methods: {
selectTab(selectedTab) {
this.tabs.forEach(tab => {
tab.isActive = (tab.name == selectedTab.name);
})
}
}
});
Vue.component('tab', {
template: `
<div v-show="isActive"><slot></slot></div>
`,
props: {
name: { required: true },
selected: { default: false }
},
data() {
return {
isActive: false
}
},
mounted() {
this.isActive = this.selected;
}
});
var app = new Vue({
el: '#app',
components: {
Example
},
data: {
form: new Form({
incidentReference: '',
streetName: '',
latitude: '',
longitude: '',
featureTypeId: 1,
archived: 0,
}),
incidents: []
},
computed: {
href() {
return '#' + this.name.toLowerCase().replace(/ /g, '-');
}
},
mounted: function () {
this.getIncidents();
},
methods: {
onSubmit() {
this.form.post('/api/v1/incidents');
},
getIncidents: function() {
console.log('getIncidents');
var self = this;
axios.get('/api/v1/incidents').then(function(response) {
// set data on vm
console.log(response.data);
var incidentsReceived = response.data.data.map(function (incident) {
return incident;
});
Vue.set(self, 'incidents', incidentsReceived);
});
}
}
});
Is it because you are using window.vue = vue;
rather than
window.Vue = vue;
OR
window.Vue = require('vue');
Related
My problem: I followed the doc from vue-chartjs but the chart is not rendering the data.
Here is my code:
My component Chart.vue
<script>
import { Line } from 'vue3-chart-v2'
export default {
extends: Line,
props: {
chartdata: {
type: Object,
default: null
},
options: {
type: Object,
default: null
}
},
mounted () {
this.renderChart(this.chartdata, this.options)
}
}
</script>
My Home.vue code:
<template>
<div class="container">
<line-chart
v-if="loaded"
:chartdata="chartdata"
:options="options"/>
</div>
</template>
<script>
import LineChart from '../components/Chart.vue'
export default {
name: 'LineChartContainer',
components: { LineChart },
data: () => ({
loaded: false,
chartdata: null,
options: {
responsive: true,
}
}),
async mounted () {
this.loaded = false
try {
const quotes = [
1, 2, 3, 4,
]
this.chartdata = quotes
this.loaded = true
} catch (e) {
console.error(e)
}
}
}
</script>
When I'm rendering the Home view, I see the axis of the chart, but no data inside...
In the console, I don't have any errors.
Later, I would like to fetch data from an API. Thus, the quotes would receive data from an external API. Here I just put some fake data for testing.
Does anyone can help me ? Thks
I was missing the import { defineComponent } from 'vue' in my component. Now it works using the below code.
<template>
<div class="container">
<line-chart
v-if="loaded"
:chartdata="chartdata"
:options="options"/>
</div>
</template>
<script>
import LineChart from '../components/Chart.vue'
import { defineComponent } from 'vue'
export default defineComponent({
name: 'LineChartContainer',
components: { LineChart },
data: () => ({
loaded: false,
chartdata: null,
options: {
responsive: true,
}
}),
async mounted () {
this.loaded = false
try {
const quotes = [
1, 2, 3, 4,
]
this.chartdata = quotes
this.loaded = true
} catch (e) {
console.error(e)
}
}
})
</script>
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)
const CustomComponent = {
props: ['index'],
template: `<span>I am a custom component: {{ index }}</span>`
};
const UserInputResult = {
components: {
CustomComponent
},
props: ['templateString'],
template: `<section v-html="templateString"></section>`
}
const app = new Vue({
el: '#app',
data(){
return {
userInput: 'user input example [:component-1]'
}
},
components: {
UserInputResult
},
methods: {
generateTemplate(){
let raw = this.userInput;
if (!!raw && raw.match(/\[\:component\-\d+\]/g)) {
let components = [...raw.match(/\[\:component\-\d+\]/g)];
components.forEach(component => {
raw = raw.replace(component, `<custom-component :index="${component.match(/\d+/)[0]}"></custom-component>`);
});
}
return raw;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<textarea v-model="userInput"></textarea>
<user-input-result :template-string="generateTemplate()">
</div>
I want to render a custom component which has a dynamical template base on user input.
when user input a specific string ([:component-1]), it will be render as a component (CustomComponent)
how to achieve this?
Thanks a lot for anyone help!
You should look into v-slot
https://v2.vuejs.org/v2/guide/components-slots.html
Example:
Parent:
<child-component v-html="myTemplate">
<span>From parent</span>
</child-component>
Child:
<div>
<v-slot></v-slot> //Will output "<span>From parent</span>"
</div>
**Added more explaination
You can then condition check and update myTemplate to your desired template. "<span>From parent</span>" is just there for explanation on how slot works.
updated by the questioner
const CustomComponent = {
props: ['index'],
template: `<span>I am a custom component: {{ index }}</span>`
};
const UserInputResult = {
template: `<section><slot></slot></section>`
}
const app = new Vue({
el: '#app',
data(){
return {
userInput: 'user input example [:component-1]'
}
},
components: {
UserInputResult,
CustomComponent
},
methods: {
generateTemplate(){
let raw = this.userInput;
if (!!raw && raw.match(/\[\:component\-\d+\]/g)) {
let components = [...raw.match(/\[\:component\-\d+\]/g)];
components.forEach(component => {
raw = raw.replace(component, `<custom-component :index="${component.match(/\d+/)[0]}"></custom-component>`);
});
}
return raw;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<textarea v-model="userInput"></textarea>
<user-input-result>
{{ generateTemplate() }}
</user-input-result>
</div>
I figured it out by using Vue.complie
according to dynamically-fetch-and-compile-a-template-with-nuxt
const UserInputResult = {
props: ['templateString'],
render(h){
return h({
components: {
CustomComponent
},
template: `<section>${this.templateString}</section>`
});
}
}
I am trying to follow this tutorial on how to use a store pattern to share state between Vue components.
In the tutorial, they initialize two separate and independent Vue instances:
var vmA = new Vue({
data: {
privateState: {},
sharedState: store.state
}
})
var vmB = new Vue({
data: {
privateState: {},
sharedState: store.state
}
})
But I am using components defined in separate .vue files in a components file, so I don't have anywhere to specify data. I can't put it in the export default block because there is already a data() entry there, for example in my component LeafletMap.vue:
<template>
<!-- ref="map" is required or Leaflet-Draw throws TypeError: "_this.$parent.$parent.$refs.map is undefined" -->
<!-- See: https://github.com/hubertokf/vue2-leaflet-draw/issues/1#issuecomment-520572130 -->
<l-map
ref="map"
v-if="showMap"
:zoom="zoom"
:center="center"
:options="mapOptions"
#update:center="centerUpdate"
#update:zoom="zoomUpdate"
>
<l-draw-toolbar position="topright"/>
<l-tile-layer
:url="url"
:attribution="attribution"
/>
</l-map>
</template>
<script>
import { latLng } from "leaflet";
import { LMap, LTileLayer } from "vue2-leaflet";
import LDrawToolbar from 'vue2-leaflet-draw-toolbar';
export default {
name: "LeafletMap",
components: {
LMap,
LTileLayer,
LDrawToolbar
},
data() {
return {
zoom: 8,
center: latLng(8.6195, 0.8248),
url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
attribution: '© OpenStreetMap contributors',
currentCenter: latLng(47.41322, -1.219482),
showParagraph: false,
mapOptions: {
zoomSnap: 0.5
},
showMap: true
};
},
methods: {
zoomUpdate(zoom) {
this.currentZoom = zoom;
},
centerUpdate(center) {
this.currentCenter = center;
}
}
};
</script>
And in my App.vue:
<template>
<div id="app">
<div id="sidebar-container">
<Sidebar />
</div>
<div id="map-container">
<LeafletMap />
</div>
</div>
</template>
<script>
// import LENIInterface from './components/LENIInterface.vue'
import LeafletMap from './components/LeafletMap.vue'
import Sidebar from './components/Sidebar.vue'
export default {
name: 'xyz',
components: {
LeafletMap,
Sidebar,
}
}
</script>
And in main.js:
import Vue from 'vue'
import App from './App.vue'
import vuetify from '#/plugins/vuetify' // path to vuetify export
// Leaflet tiles are scrambled unless you add this import
// See https://stackoverflow.com/questions/58723390/vue-leaflet-map-tiles-in-wrong-order
import "leaflet/dist/leaflet.css";
// import "./assets/css/main.css";
Vue.config.productionTip = false
var store = {
debug: true,
state: {
message: 'Hello!'
},
setMessageAction (newValue) {
if (this.debug) console.log('setMessageAction triggered with', newValue)
this.state.message = newValue
},
clearMessageAction () {
if (this.debug) console.log('clearMessageAction triggered')
this.state.message = ''
}
}
new Vue({
data: {
privateState: {},
sharedState: store.state
},
vuetify,
render: h => h(App),
}).$mount('#app')
So how can I pass this state store object down to the subcomponents when they are organized like this?
Just create a file called store.js:
export default {
state: {
message: 'Hello!'
},
methods: {
setMessageAction (newValue) {
if (this.debug) console.log('setMessageAction triggered with', newValue)
this.state.message = newValue
},
clearMessageAction () {
if (this.debug) console.log('clearMessageAction triggered')
this.state.message = ''
}
}
}
And import it in your LeafletMap.vue:
<script>
import { latLng } from "leaflet";
import { LMap, LTileLayer } from "vue2-leaflet";
import LDrawToolbar from 'vue2-leaflet-draw-toolbar';
import store from './stores/store.js';
export default {
name: "LeafletMap",
components: {
LMap,
LTileLayer,
LDrawToolbar
},
data() {
return {
zoom: 8,
center: latLng(8.6195, 0.8248),
url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
attribution: '© OpenStreetMap contributors',
currentCenter: latLng(47.41322, -1.219482),
showParagraph: false,
mapOptions: {
zoomSnap: 0.5
},
showMap: true
...store.state
};
},
methods: {
zoomUpdate(zoom) {
this.currentZoom = zoom;
},
centerUpdate(center) {
this.currentCenter = center;
}
...store.methods
}
};
</script>
I'm trying to use vue-async-data to fetch data asynchronously before rendering my Vue component, but I'm having no success. I'm not getting any erros, but it simply doesn't work.
Here's my main.js code:
import Vue from 'vue'
import VueAsyncData from 'vue-async-data'
import router from './router'
import App from './App.vue'
Vue.use(VueAsyncData)
new Vue({
el: '#app',
router,
template: '<App/>',
components: { App }
})
And here's my App.vue code:
<template>
<div>
{{ msg }}
<navigation wait-for="async-data"></navigation>
</div>
</template>
<script>
import Navigation from './components/Navigation.vue'
export default {
name: 'app',
components: {
Navigation
},
data: function() {
return {
msg: 'not loaded yet...'
}
},
asyncData: function (resolve, reject) {
// load data and call resolve(data)
// or call reject(reason) if something goes wrong
setTimeout(function () {
// this will call `vm.$set('msg', 'hi')` for you
resolve({
msg: 'hi'
})
}, 1000)
}
}
</script>
The msg value doesn't change at any moment, but the component is still rendered.
Am I missing somenthing?
As Bert Evans stated, vue-async-data doesn't work with Vue 2.0.
I used vue-router and the created function to achieve what I needed (as suggested in: https://router.vuejs.org/en/advanced/data-fetching.html.
<template>
<div>
<div class="loading" v-if="loading">
Loading...
</div>
<div v-if="error" class="error">
{{ error }}
</div>
<navigation v-if="currentUser"></navigation>
</div>
</template>
<script>
import Navigation from './components/Navigation.vue'
export default {
name: 'app',
components: {
Navigation
},
data: function() {
return {
loading: true,
error: false,
currentUser: null
}
},
created: function() {
this.fetchUserData()
},
methods: {
fetchUserData: function() {
this.$http.get('/Account/CurrentUserInfo').then(data => {
this.currentUser = data
this.loading = false
}, response => {
this.loading = false
this.error = true
});
}
}
}
</script>