Message Vue is not defined - vue.js

I'm new to studying vue so my question may be kind of silly, but why am I getting the message "vue is not defined"? in this code:
<template>
<div id="app">
<input></input>
<button>{{ textoBotao }}</button>
</div>
</template>
<script>
new Vue({
data: {
a: 1
},
created: function () {
console.log('a é: ' + this.a)
}
})
export default ({
data() {
return{
textoBotao: 'Clique aqui'
}
}
})
</script>

In your code, you don't need to create another instance of Vue. I can't imagine a situation where you need to create a new Vue instance in a single file component. Uou can use components if you need to encapsulate some functionality
If you do need to do this, you can use the following code:
import Vue from 'vue'
new Vue({
...
})
please see vue's official documentation and sample projects

Old question, but if someone needs it
If you have new Vue({}) in a js file and you load that js file before loading vuejs javascript file, you will get this error. This was the reason for my error.
Basically add /vue.min.js"> before you add other js files using vuejs
Hope it helps

I think You miss to add vue.js file, example:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.18/vue.min.js"></script>

Related

Trying to use ref inside a Vue single file component. Got undefined

I'm beginning with vuejs and I try to figure what could be done about reference of child component instance in root instance. I used ref attribute and it works pretty well, except if I use it in a single file component (in the template tags). In this specific case, I get 'undefined'.
So, I try to understand why, because it could be very useful for establishing dynamic references. I could probably bypass that situation easily, but I would like to understand the problem instead of run away.
So if someone have an idea ;)
I am using webpack to import my single file component in my app.js and compiled it. However the template compilation isn't done by webpack, but by the browser at runtime (maybe it's the beginning of an explanation ?).
My app is very simple, and I log my references on click on the header, so I don't think it's lifecylce callback related.
Here is my files :
app.js
import Vue from 'Vue';
import appButton from './appButton.vue';
import appSection from './appSection.vue';
var app = new Vue({
el: '#app',
components:
{
'app-button' : appButton
},
methods:
{
displayRefs: function()
{
console.log(this.$refs.ref1);
console.log(this.$refs.ref2);
console.log(this.$refs.ref3);
}
}
});
my component appButton.vue
<template>
<div ref="ref3" v-bind:id="'button-'+name" class="button">{{label}}</div>
</template>
<script>
module.exports =
{
props: ['name', 'label']
}
</script>
my index.html body
<body>
<div id="app">
<div id="background"></div>
<div id="foreground">
<img id="photo" src="./background.jpg"></img>
<header ref="ref1">
<h1 v-on:click="displayRefs">My header exemple</h1>
</header>
<nav>
<app-button ref="ref2" name="presentation" label="Qui sommes-nous ?"></app-button>
</nav>
</div>
</div>
<script src="./app.js"></script>
</body>
ref1 (header tag) and ref2 (app-button tag) are both found. But ref3 (in my single file component) is undefined. Also
Thanks for all the piece of answer you could give me, hoping it's not a silly mistake.
A ref you set is only accessible in the component itself.
If you try to console.log(this.$refs.ref3); into a method from appButton.vue, it will work. But it won't work in the parent.
If you want to access that ref from the parent, you need to use the $ref2 to access the component, and then use the $ref3. Try this:
var app = new Vue({
el: '#app',
components:
{
'app-button' : appButton
},
methods:
{
displayRefs: function()
{
console.log(this.$refs.ref1);
console.log(this.$refs.ref2);
console.log(this.$refs.ref2.$refs.ref3); // Here, ref3 will be defined.
}
}
});
Accessing some child ref from the parent is not supposed to be a good practice tho.

After laravel-mix upgrade app no longer sees global vars

I'm upgrading a project from laravel-mix v2.0 to v4.0 and I'm seeing an issue now where at runtime my components can't see globally scoped variables like they did before. How can upgrading the build tool impact the runtime?
I see I can add instance properties to the vue prototype, but is that really the approach I need to take? Seems like it should still be able to read global variables like it did before.
html
<script type="text/javascript">
var games = [
// a bunch of objects
];
</script>
<script src="{{ mix('js/app.js') }}"></script>
app.js
import ChannelSubscriptionSlider from './components/guild-subscriptions/ChannelSubscriptionSlider.vue';
Vue.component('channel-subscription-slider', ChannelSubscriptionSlider);
ChannelSubscriptionSlider.vue
import Vue from 'vue';
import VueResource from 'vue-resource';
Vue.use(VueResource);
export default {
data: function () {
return {
games: games, // undefined when used within this component, but used to work before upgrade
}
},
Edit 2
Use `window.games, this would "register" your variables globally.
Although, what i do, is the following, consider a MPA not a SPA:
In app.js i just leave the following lines:
require('./bootstrap');
window.Vue = require('vue');
In a separate file, called main.js that i made, i put this, as an example:
import Sidebar from './components/layouts/Sidebar.vue'
import Topnav from './components/layouts/Topnav.vue'
new Vue({
el: '#sidebar',
render: h => h(Sidebar)
});
new Vue({
el: '#topnav',
render: h => h(Topnav)
});
at the end of app.blade.php i put:
<script src="{{ asset('js/app.js') }}"></script>
<script type="text/javascript">
const user_props = {
fullName : {!! json_encode(Auth::user()->fullName) !!},
username : {!! json_encode(Auth::user()->username) !!},
}
user_props.install = function(){
Object.defineProperty(Vue.prototype, '$userProps', {
get () { return user_props }
})
}
Vue.use(user_props);
</script>
<script src="{{ asset('js/main.js') }}"></script>
This works because i mount vue in app.js but the components that use user_props are loaded after i declare and install the prototype... Also, since vue is mounted in app.js i can use Vue.use(user_props); after loading it...
And forgot to mention that in webpack.mix.js you should add the main.js:
mix.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css')
.js('resources/js/main.js', 'public/js/')
Edit 1
Based on your comments, and the docs: https://v2.vuejs.org/v2/cookbook/adding-instance-properties.html#The-Importance-of-Scoping-Instance-Properties
The $ is just a convention:
... We scope instance properties with $ to avoid this. You can even use your own convention if you’d like, such as $_appName or ΩappName, to prevent even conflicts with plugins or future features.
So with that in mind you could set it up as:
Vue.prototype.games = games;
then you can access it on every component as this.games
As the documentation implies, when doing this you've got to be careful to not overwrite it. So if you have it declared on the data section of your Vue components i think you should delete those lines...

Nested single file components - vue.js with electron-forge

I am trying electron for the first time and I am blown away by it. I have hit a wall, though, when trying to use single file vue.js components using electron-forge. My problem is the following:
I create a project using the vue.js template and run it. Works and looks great. I have a single file page with an index file that looks like this:
<div id="test"></div>
</body>
<script>
import Vue from 'vue';
import Test from './test';
const app = new Vue(Test).$mount('#test');
app.text = "Electron Forge with Vue.js!";
</script>
So far, so good. It imports Test, which is a single file component and renders it.
Now, I would like to have other single file components nested in this main component. For example, I would like to have the following, in my app file called test.vue
<template>
<h2>Hello from {{text}}</h2>
</template>
<script>
import About from './About.vue'
export default {
components: {
appAbout: About,
},
data () {
return {
text: 'Electron'
}
}
}
</script>
Again, so far so good. I can run the app with no errors so the component is being imported.
Here comes my problem: if I now try to render the component using <appAbout></appAbout>, as I have done before in web apps with vue.js, I get the following error.
It basically says that I am not using a single root element in my component, which is really strange because my component looks like this:
<template lang="html">
<div>Hello from component</div>
</template>
<script>
export default {
}
</script>
<style lang="css">
</style>
I am stuck. Can someone please help?
So I have tried a few different things with no success, like using or even as the component names.
I also have tried these two ways of starting the vue:
The way you get with electron-forge
const app = new Vue(App).$mount('#app')
and the way I learned
new Vue({el: '#app', render: h => h(App)})
Nothing seems to work...
Define your component like this :
export default {
components: {
'app-about': About
}
}
Then use it in template like this (with kebab-case) :
<app-about></app-about>
About your compiling template error you need to wrap everything in test.vue in a root element :
<template>
<div>
<h2>Hello from {{text}}</h2>
<app-about></app-about>
</div>
</template>

How to Access Vue-Loader Components in an HTML File

I would like to use the modular style and file format of Vue Loader (i.e., where I have a template section, script section and style section in each .vue file).
What I can't figure out how to do (or if it is even possible to do) is use my custom templates in an html file.
For instance, in the App.vue file I can use the following code:
<template>
<div id="app">
<message>Hello there</message>
</div>
</template>
This will work to display a custom message component on the home page.
What I would like to do instead is use my custom components in html files. For instance, in the index.html file to use the following code:
<div id="app">
<message>Hello there</message>
</div>
Any idea how I can do this? Thanks.
NOTE: I am new to Vue Loader and semi-new to Vue (so I apologize in advance if the answer to this question is obvious).
There are many ways you can compile a single file component and then use that component in a web page.
Use vue-cli
Vue released a command line interface tool called vue-cli that can initialize projects and build components with zero configuration. One option to build a component that you can use in your page is to use vue build.
vue build MyComponent.vue --prod --lib MyComponent
This will compile a script that exposes MyComponent. If you include that script in your page and then add it globally,
Vue.component(MyComponent)
That component will be available to you in any of your Vues.
Make a plugin
Here is a sample of a very basic framework for making a plugin.
myPluginDefinition.js
window.MyPlugin= {};
MyPlugin.install = function (Vue) {
Vue.component('my-component', require('./my-component.vue'));
}
webpack.config.js
module.exports = {
entry: "./myPluginDefinition.js",
output: {
path: __dirname+'/dist',
filename: "MyPlugin.js"
},
module: {
loaders: [
{
test: /\.vue$/,
loader: 'vue-loader',
}
]
}
};
This will build a file called MyPlugin.js that will contain each of the single file components that you include in the install function. Include the script on your page and then call
Vue.use(MyPlugin)
and you will have all of your components.
Use a custom webpack configuration
There are many ways you could configure webpack to build your single file components. You could build them all into a single file or build them separately. I suggest if you want to use one of these options you ask a separate question.
Actually you can do this easily by:
register your component :
Vue.component('message', {
template: '<div>A custom component!</div>'
});
then comment the render function in your Vue instance like so:
new Vue({
el: '#app',
// render: h => h(App)
})
after that you will be able to render your message Tag like this:
<div id="app">
<message></message>
</div>
Edit :
if you don't want to use this way you can define it in your view instance:
new Vue({
el: '#app',
// render: h => h(App)
components: {
message: {
template: `
<h1>Hello World</h1>
`
}
}
})
Import desired component definition object and pass it to options.components
<template>
<some-component></some-component>
</template>
<style>...</style>
<script>
import SomeComponent from 'path/to/some-component.vue';
export default {
components: {
// ES2015 shorthand for SomeComponent: SomeComponent
SomeComponent
}
}
</script>
That leverages local component registration
Both the default export and SomeComponent are component definition objects.

Testing .vue components (Browserify, jasmine, vueify). Why do I need a wrapper div?

I have finally been able to test .vue components the way I want to, however, I'm a little confused by a couple of things I had to add in order to get it working - any explanations would be great. This is testing child components too.
Using the vueify-template 1.0, I altered the Hello.vue to be this
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<child></child>
</div>
</template>
<script>
import Vue from 'vue'
import Child from './Child.vue'
export default Vue.extend({
data () {
return {
msg: 'Hello World!'
}
},
components: {
Child
}
})
</script>
Child looks like this:
<template>
<div class="child">
Child Content
</div>
</template>
<script>
import Vue from 'vue'
export default Vue.extend({
})
</script>
Now I can test these the way I want to with:
import Vue from 'vue'
import Hello from '../../src/components/Hello.vue'
describe('Hello.vue', () => {
it('should render correct contents into el', () => {
var mount = document.createElement('div');
const vm = new Hello({
el: mount,
});
expect(vm.$el.querySelector('.hello h1').textContent).toBe('Hello World!')
expect(vm.$el.querySelector('.hello .child').textContent.trim()).toBe('Child Content')
})
})
Now - a few questions if anyone has time to answer, I'm quite new to Vue & ES6 etc. so apologies if they're obvious!
I had to do the export default Vue.extend({ .... }) before I was able to mount the components in my test. Does this matter? The app seems to perform identically so I'm not really sure what's going on here.
The main gotcha was that in my <template> if I didn't have the correctly named wrapper div class (e.g. <div class="child">) then nothing would be generated into the vm.$el . Oddly (to me) if I have exactly the same test, but don't include the <child></child> tag, then the vm.$el will be at least created... so I'm somewhat confused.
Is this an evil way to test? Am I fighting the framework?
Thanks for any and all pointers - I hope this isn't too generic a question for SO.