'Vue not defined' issue in combination with RequireJS - vue.js

I have an issue where the Vue object is undefined in the browser, after I load in Vue with RequireJS. I'm not sure what's going on, I hope someone has some pointers to focus on.
Something worth noting is that I'm placing this code through our custom framework into a MVC C# application. Ultimately the code is placed in views and served along all other JS / HTML.
The HTML is placed first, after which the script is executed.
HTML:
<div id="aapje">
{{ message }}
</div>
JS:
require(['https://unpkg.com/vue'], function() {
var appje = new Vue({
el: '#aapje',
data: {
message: 'Hello Vue!'
}
});
});
Console dump:
Codepen: https://codepen.io/olafjuh/pen/oKWKXG

To achieve expected result, pass 'Vue' as parameter to callback funtion of require
working code sample
require(['https://unpkg.com/vue'], function(Vue) {
var appje = new Vue({
el: '#aapje',
data: {
message: 'Hello Vue!'
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.3/require.min.js"></script>
<div id="aapje">
{{ message }}
</div>
codepen - https://codepen.io/nagasai/pen/WVjVoV

Related

VueJs: bind `v-on` on a custom component to replace an existing one

In order to ease the styling of my page, I'd like to create a bunch of mini components like, and exploit how attributes are merged in VueJs. So for example, here is a minimal js file also hosted on this JSFiddle:
Vue.component('my-button', {
template: '<button style="font-size:20pt;"><slot></slot></button>'
})
var app = new Vue({
el: "#app",
data: {
message: "world",
},
methods: {
sayHello: function () {
alert("Hello");
}
}
})
and then in my html I just want to use <my-button> instead of button:
<div id="app">
Hello {{message}} <my-button #click="sayHello" style="color:red;">Style works, but not click</my-button> <button v-on:click="sayHello" style="color:red;">Both works</button>
</div>
Unfortunately, it seems that attributes are merged, but not listeners, so it means that I can't do v-on:click on my new button... Any way to make it possible?
Thanks!
-- EDIT --
I saw the proposition of Boussadjra Brahim of using .native, and it works, but then I found this link that explains why it's not a great practice and how to use v-on="$listeners" to map all listeners to a specific sub-button. However, I tried, to just change my template with:
template: `<button style="font-size:20pt;" v-on="$listeners"><slot></slot></button>`,
but I get an error:
Vue warn: Property or method "$listeners" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option."
Here is the JSFiddle.
Your fiddle didn't work because you were using an old version of Vue, $listeners was added in Vue 2.4.0.
Here's a demo:
Vue.component('my-button', {
template: '<button style="color: red" v-on="$listeners"><slot/></button>'
})
new Vue({
el: '#app',
methods: {
sayHello() {
alert('Hello')
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<my-button #click="sayHello">Custom Button</my-button>
<button #click="sayHello">Ordinary Button</button>
</div>

vuejs-paginator example html markup

I have a pretty daft question re: vuejs-paginator but I am having a hard time getting to run this example (I am a backend dev here).
So, I have on my head:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuejs-paginator/2.0.0/vuejs-paginator.js"></script>
Then as described in the page, I have:
<script>
new Vue({
el: '#app',
data () {
return {
// The resource variable
animals: [],
// Here you define the url of your paginated API
resource_url: 'http://hootlex.github.io/vuejs-paginator/samples/animals1.json'
}
},
components: {
VPaginator: VuePaginator
},
methods: {
updateResource(data){
this.animals = data
}
}
});
</script>
Now, what the F I should have in my HTML, I have no clue, and the author seems to say, I use:
<v-paginator resource_url="api/animals" #update="updateResource"></v-paginator>
but, this I think is just for the pagination. What shoud the app element contain and where is it? The docs dont seem to show this? he author then shows some random markup:
<ul>
<li v-for="animal in animals">
{{ animal.name }}
</li>
</ul>
Where should this go? Should I have an app div element?
You can add content to your app by adding it to the template key:
<script>
new Vue({
el: '#app',
data () {
return {
// The resource variable
animals: [],
// Here you define the url of your paginated API
resource_url: 'http://hootlex.github.io/vuejs-paginator/samples/animals1.json'
}
},
components: {
VPaginator: VuePaginator
},
methods: {
updateResource(data){
this.animals = data
}
},
template: `
<div>
<ul>
<li v-for="animal in animals">
{{ animal.name }}
</li>
</ul>
<v-paginator :resource_url="resource_url" #update="updateResource"></v-paginator>
</div>
`
});
</script>
Something like that.
You also need an initial <div id="app"></div> in your html. This is the element where Vue will mount the app and load the content.
EDIT
The plugin uses this.$http which requires some kind of dependency that it doesn't specify.
I have made an alteration in the following codepen and it works properly now:
https://codesandbox.io/s/competent-dream-zngzt

Variable and method checking in Vue

One of the canonical examples on Vue website is:
<div id="app-5">
<p>{{ message }}</p>
<button v-on:click="reverseMessage">Reverse Message</button>
</div>
var app5 = new Vue({
el: '#app-5',
data: {
message: 'Hello Vue.js!'
},
methods: {
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})
My problem is that if I rename the reverseMessage function, there is no error at compile time to notify me about this. Is there a way to receive an error at compile time when this happens?
Just a side note, although not really relevant: I am using Vue in conjunction with Typescript.
Thank you!

Load default value from HTML input to vue.js data

I wonder if it is possible to load value of tag value as default value for vue.js data?
Works fine with
coupon: $('#coupon').val(),
but I really do not want to use jQuery.
Code is available here: https://jsfiddle.net/4a80dnfo/1/
So I found a way to get this done using the beforeMount() hook.
Assuming this HTML:
<div id="coupon-code">
<input ref="coupon" v-model="coupon" value="99PI_ORG" />
</div>
This Javascript should get the job done:
new Vue({
el: '#coupon-code',
data: {
coupon: ''
},
beforeMount: function() {
this.coupon = this.$el.querySelector('[ref="coupon"]').value;
}
// methods and such here.
}
});
I ended up using the beforeMount() hook after some trial an error. Some things I've learned which may be relevant:
this.$refs does not exist in the created() hook.
this.$refs.coupon.value returns an empty string in the mounted() hook.
The ref attribute of an element is deleted before the mounted() hook, so something like this.$el.querySelector('input[ref=coupon]') does not work.
You can use this.$el.querySelector('input[data-ref=coupon]').attributes['value'].value inside mounted(), but this seems worse to me than using beforeMount().
If anyone has suggestions on how to do this better, I'm very open to feedback. This solution still feels sub-optimal to me.
In your jsfiddle you are using v-model, so in your data() you just have to set your desired value
Edit: updated code to use v-bind
new Vue({
el: '#app',
data: {
coupon: 'You value here',
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.js"></script>
<div id="app">
<input id="coupon" type="text" name="coupon" :value="coupon" />
</div>
<input name="coupon" v-model="coupon" value="def val">
window.app = new Vue({
el: '#xxx',
data: {
coupon: document.querySelector("input[name=coupon]").value
}
...
});

How to make Vue js directive working in an appended html element

I have a Vue directive added in an appended html element like v-on directive but it's not working on my end. Basically I want to know the equivalent of .on() in jquery.
"Vue.js compilation happens when you instantiate/mount the root instance. It doesn't detect new DOM being injected unless it is a result of a directive (e.g. v-repeat, v-partial will dynamically create new DOM fragments)."
https://github.com/vuejs/Discussion/issues/77
You have to compile your newly added element like this:
html:
<div id="app">
<button v-on="click: addNewElement()">Add Element</button>
<br />
</div>
JavaScript
new Vue({
el: '#app',
data: {
sampleElement: '<button v-on="click: test()">Test</button>'
},
methods:{
addNewElement: function(){
var element = $('#app').append(this.sampleElement);
/* compile the new content so that vue can read it */
this.$compile(element.get(0));
},
test: function(){
alert('Test');
}
}
});
See this working Fiddle on Firefox: http://jsfiddle.net/chrislandeza/syewmx4e/
Update
$compile has been removed on Vue 2.x
I've seen people suggesting Vue.compile or
var tmp = Vue.extend({
template: 'Content'
})
new tmp().$mount(' id or refs ')
But those 2 does not behave like the old $compile.
For Vue 2.x, the new solution is referenced here in the doc : https://v2.vuejs.org/v2/api/#vm-mount (see 'Example').
Custom example :
var MyComponent = Vue.extend({
template: '<div v-on:click="world">Hello!</div>',
methods : {
world : function() {
console.log('world')
}
}
})
var component = new MyComponent().$mount()
document.getElementById('app').appendChild(component.$el)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="app"></div>
Works like a charm!
You need to register the html as a template of the component.