Import .vue file - javascript

I have main.js and app.vue file
main js file inner look like this
var a = 1;
import App from './App.vue'
new Vue({
el: '#app',
render: h => h(App)
})
in App.vue file i want to console.log(a)
return error a is not defined why ? What is wrong ?

You need to export the variable, and then import it into another file where you want it. The best way to do that would be to put the variable a in its own module file. This allows you to avoid using global variables, which pretty much negate the purpose of modules!
a.js:
export const a = 'foo'
App.vue:
<script>
import { a } from './a.js'
console.log(a) // foo
console.log(1)
export function log3() {
console.log(3)
}
</script>
main.js:
import { log3, default as App } from './App.vue'
console.log(2)
log3()
new Vue({
el: '#app',
render: h => h(App)
})
import { a } from './a.js'
console.log(a) // foo
Here is what will be logged to the console:
'foo' (from App.vue)
1 (from App.vue)
2 (from main.js)
3 (from main.js calling the function log3 from App.vue)
'foo' (from main.js)
Now both App.vue and main.js have access to a, because they have explicitly imported it. The fact that App.vue has access to a has nothing to do with the fact that main.js also has access to a.

The simplest thing you can do I guess is define data properties insode root instance, and access them as this.$root.myProperty from components:
new Vue({
el: '#app',
data: {
myGlobal: 'Hi there'
},
components: {
'child' : {
template: `<p>{{ text }}</p>`,
data: function() {
return {
text: this.$root.myGlobal
}
}
}
}
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
<child></child>
</div>
Another option - a simple plugin as a central storage: https://stackoverflow.com/a/44517332/7636961

a is not defined in your App component but directly in main.js.
You may want to use a global variable. (see also this thread for global variable in vuejs)

Related

Can't pass data from main.js to App.vue in Vue js?

In my main.js I do authentication and after that I populate a data property. I'm trying to pass that data property to the App component but seems not possible?
main.js
import Vue from 'vue'
import App from './App.vue'
new Vue({
data: {
test: 'test'
},
//render: h => h(App)
render: h => h(App, { props: { 'test': this.test }})
}).$mount('#app')
App.vue
<template>
<div id="app" :test="test">
<h1>{{test}}</h1>
</div>
</template>
<script>
export default {
name: 'app',
props: ['test']
}
</script>
Just gives error as test and/or this.test is undefined. Passing a hard-coded value works. Without using props on the render line has no errors but App doesn't receive data. Am I just doing it wrong?
You can set render to a normal function in order for this to refer to the Vue instance:
render: function (h) {
return h(App, { props: { test: this.test } });
}
Your problem is that you're defining render as an anonymous arrow function. which means that it's this context isn't bind to you Vue instance. if you want a function's context to be the "hosting" object, you must define it with the function syntax.
new Vue({
data: {
test: 'test'
},
render(h) {
return h(App, { props: { 'test': this.test }})
}
}).$mount('#app')
you can read about arrow function vs regular functions here

use vuejs variable in pure javascript file

I'm practicing laravel with vuejs and I'm wondering if possible to use vuejs (component) variable in other file with pure javascript.
I created my.js and registered it in app.js.
require('./my.js');
const app = new Vue({
el: '#app'
});
In my.js I have following code.
alert(app.name)
name is variable used in vuejs component. As a result I received alert undefined. Please give me some guidelines.
You must run the code in the correct order:
function MyFunc(vm) {
alert(vm.name)
}
const app = new Vue({
data: {
name: 'FooBar'
}
});
MyFunc(app)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
Example 1
my.js:
export default function(vm) {
alert(vm.name);
}
main.js:
import Vue from "vue";
import MyFunc from './my';
const app = new Vue({
data: {
name: 'FooBar'
}
});
MyFunc(app)
Example 2
my.js:
export default (app) => alert(app.name);
vue.js:
import Vue from 'vue';
export default new Vue({
data: {
name: 'FooBar'
}
});
main.js:
import bar from './vue'
import foo from './my'
foo(bar)

Creating the root Vue instance inside of a Vue file

Is there a way for a .vue file to be responsible for creating its own Vue instance in a Single File Component pattern?
Here's the Vue File.
// MyComponent.vue
<template><div>Hello {{ name }}!</div></template>
<script>
const Vue = require('vue');
// what would usually be exports default
const componentConfig = {
name: "my-component",
props: {
name: String,
},
};
function create(el, props) {
const vm = new Vue({
el,
render(h) {
return h(componentConfig, { props });
});
vm.$mount();
return vm;
}
module.exports = { create };
</script>
and then the usage in some JS file:
// index.js
const MyComponent = require('./MyComponent.vue');
const el = '.container';
const props = {
name: 'Jess',
};
MyComponent.create(el, props);
</script>
When I do the above, I get errors about not being able to find the template.
[Vue warn]: Failed to mount component: template or render function not defined.
found in
---> <MyComponent>
<Root>
Like instinctually, I don't understand how the Vue compiler would be able to magically deduce (from within the script tags) that I want to reference the template declared above... so.. yeah. Is there an explanation for why I can't do this, or thoughts on how I could get it to work?
What you are describing is done in a pre-compilation step through Webpack and Vue Loader. The Vue compiler doesn't actually parse Single File Components. What the Vue compiler can parse is templates provided in a component’s options object. So if you provide a template option in your componentConfig object your example will work. Otherwise you'll have to go through the pre-compilation step with Webpack and Vue Loader to parse a Single File Component's template. To do that you'll have to conform to the SFC structure defined in the spec. Here's an excerpt ..
Template
Each *.vue file can contain at most one <template> block at a
time.
Contents will be extracted and passed on to vue-template-compiler and
pre-compiled into JavaScript render functions, and finally injected
into the exported component in the <script> section.
Script
Each *.vue file can contain at most one block at a time.
The script is executed as an ES Module.
The default export should be a Vue.js component options object.
Exporting an extended constructor created by Vue.extend() is also
supported, but a plain object is preferred.
Any webpack rules that match against .js files (or the extension
specified by the lang attribute) will be applied to contents in the
<script> block as well.
To make your specific example work You can re-write main.js file like this ..
const MyComponent = require("./MyComponent.vue");
const el = ".container";
const data = {
name: "Jess"
};
MyComponent.create(el, data);
And your MyComponent.vue file (This could just as well be a js file as #Ferrybig mentioned below) ..
<script>
const Vue = require('vue');
function create(el, data) {
const componentConfig = {
el,
name: "my-component",
data,
template: `<div>Hello {{ name }}!</div>`
};
const vm = new Vue(componentConfig);
return vm;
}
module.exports = { create };
</script>
See this CodeSandbox
Or if you prefer render functions your MyComponent.vue will look like this ..
<script>
const Vue = require('vue');
function create(el, data) {
const componentConfig = {
el,
name: "my-component",
data,
render(h) { return h('div', 'Hello ' + data.name) }
};
const vm = new Vue(componentConfig);
return vm;
}
module.exports = { create };
</script>
CodeSandbox
One last thing to keep in mind: In any component you can use either a template or a render function, but not both like you do in your example. This is because one of them will override the other. For example, see the JSFiddle Vue boilerplate and notice how when you add a render function the template gets overridden. This would explain that error you were getting. The render function took precedence, but you fed it a component's options object that provides no template to be rendered.
You are really close to a working solution, but you are missing just some "glue" parts to combine everything together:
<template>
<div>Hello {{ name }}!</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld";
import Vue from "vue";
const Component = {
// Add data here that normally goes into the "export default" section
name: "my-component",
props: {
name: String,
},
data() {
return {
};
},
};
Component.create = function(el, props) {
const vm = new Vue({
el,
render(h) {
return h(Component, { props });
},
});
vm.$mount();
return vm;
};
export default Component;
</script>
This can then be used as follows in other files:
import App from "./App";
App.create("#app", {
name: 'Hello World!',
});
Example on codesandbox: https://codesandbox.io/s/m61klzlwy

Vue JS Component Uncaught ReferenceError: Vue is not defined

I am new in vue js, I am learning components. I have created a basic program containing component. Following are my files
project/src/main.js
import Vue from 'vue'
window.Vue = Vue;
import ButtonCounter from './components/ButtonCounter.vue'
new Vue({
el: '#components-demo',
render: h => h(ButtonCounter)
})
project/src/components/ButtonCounter.vue
<template>
<div id="components-demo">
<button-counter></button-counter>
</div>
</template>
<script>
// Define a new component called button-counter
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
</script>
When I execute this, I get following error, even though I have declared Vue globally in main.js
So it looks like you took the component definition and just moved to another file. If you move to another file you don't need to use Vue.component. You just export an object containing the data, methods, etc. that you want attached to the component. And inside the Vue instance you attach the imported component via the components property. I.e.
Main index.html
<div id="components-demo">
<button-counter></button-counter>
</div>
Component.vue
<template>
<button v-on:click="count++">You clicked me {{ count }} times.</button>
</template>
<script>
export default {
data: function () {
return {
count: 0
}
}
})
</script>
Then inside your main file
import Vue from 'vue'
// window.Vue = Vue; -- don't need this anymore
import ButtonCounter from './components/ButtonCounter.vue'
new Vue({
el: '#components-demo',
render: h => h(ButtonCounter),
components: {ButtonCounter}
})
The error is in this line
window.Vue = Vue;
Just import and create a new instance of Vue
import Vue from 'vue'
import ButtonCounter from './components/ButtonCounter.vue'
new Vue({
el: '#components-demo',
render: h => h(ButtonCounter)
})

Can't access root data in VueJS

It's my first post on stackoverflow, so sorry in advance if I do something incorrectly. My question;
I've setup a VueJS project, and I'm trying to reach data that I put in the App.vue from another component. To do this, I use this.$root.count for example, but it returns undefined.
Main.js:
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App'
Vue.use(VueRouter);
const router = new VueRouter({
mode: 'history',
routes: [{
path: '/',
name: 'home',
component: function (resolve) {
require(['./components/Hello.vue'], resolve)
}
}, {
path: '/race-pilot',
name: 'racePilot',
component: function (resolve) {
require(['./components/RacePilot.vue'], resolve)
}
}
});
new Vue({
el: '#app',
router,
template: '<App/>',
components: { App }
});
App.vue:
<template>
<div>
<div class="menu" ref="menu">
<router-link :to="{ name: 'home' }">Home</router-link>
<router-link :to="{ name: 'racePilot' }">Race Pilot</router-link>
</div>
<div id="app">
<router-view></router-view>
</div>
</div>
</template>
<style src="./assets/css/app.scss" lang="scss"></style>
<script>
import Hello from './components/Hello'
export default {
name: 'app',
components: {
Hello
},
data () {
return {
count: '0'
}
}
}
</script>
RacePilot.vue:
<template>
<div class="race-pilot">
</div>
</template>
<script>
export default {
name: 'RacePilot',
mounted() {
console.log(this.$root.count);
}
}
</script>
So the last log returns undefined. However, if I log this.$root, I do get the object. Anybody any idea? Thanks in advance!
Vuex is fine and all, but if you just want to expose a property to all of your views in a router based app, you can set it on the router-view.
<router-view :count="count"></router-view>
Then your view component just needs to accept it as a prop.
export default {
props:["count"],
name: 'RacePilot',
mounted() {
console.log(this.count);
}
}
this.$root references the top level Vue instance (new Vue...) and not the App VueComponent.
it is really hacky, other solutions are preferable, but this could work:
new Vue({
el: '#app',
router,
template: '<App/>',
components: { App },
methods: {
getCount() {
return this.$children[0].count
}
},
});
and using getCount() in RacePilot.vue:
export default {
name: 'RacePilot',
mounted() {
console.log(this.$root.getCount());
}
}
You are trying to access data which is stored in App.vue but this data will be local to the component and not accessible globally.
App.vue is not the root instance (referred to by $root), instead it is the first component within the root instance which is actually created at main.js. It is during this creation time, you need to pass the data which will then be exposed for all child components via $root.
Here is the relevant portion of main.js, modified accordingly :-
new Vue({
el: '#app',
data: { count: 0 },
router,
template: '<App/>',
components: { App }
});
Tip : To confirm that App.vue is indeed the first child of root instance, try comparing the references of this.$root with this.$parent. It should returntrue which means that root instance is the parent of App.vue.
References :-
https://v2.vuejs.org/v2/guide/instance.html
https://v2.vuejs.org/v2/api/#vm-root
https://v2.vuejs.org/v2/guide/components-edge-cases.html#Accessing-the-Root-Instance
It should had worked as it is, as it is working here.
However a better way to manage global variables, which are available across components should be solved by state machine. Vue has Vuex for that purpose as stated here.
You should not do it like that.
Definitely you should not try to access other components like that.
To share data between components you can either use props (one-way binding) or Vuex to make data accessible and editable from all components through store.
You can use global $store or $router if you will start your Vue app this way:
new Vue({
el: '#q-app',
router,
store
render: h => h(require('./App'))
})
Then you can access store (for state change or access state (do not mutate state this way)) - this.$store.state.yourStaneName
You can also make the App component the actual root by passing the component directly to the Vue instance, which would look something like this:
new Vue(App).$mount('#app')
You'll probably have to move the router to App.vue, but this will make sure that this.$root will resolve to your App component directly.

Categories