I'm currently trying VueJS 2 and noticed a change when using it on existing DOM
Indeed everytime VueJS is initialised it will do something on existing DOM and will remove events previously binded outside of VueJS.
// We bind an event
document.querySelector('#demo').addEventListener('click', function () {
alert("i'm a button")
})
// and it's lost when Vue is binded
new Vue({
el: '#vuejs'
})
This same example works fine with VueJS1. I don't have enough understanding of Vue core to understand what changed between the two version of the compiler.js
that would explain this change.
Is there a reason why you can't use Vue events instead?
<div id="vuejs">
<div>
<button id="demo" @click="var1 += 'a'">Bouton</button>
</div>
<div id="demo_content">
{{ var1 }}
</div>
</div>
new Vue({
el: '#vuejs',
data: {
var1: 'Hello world'
}
})
Vue works under the assumption that you do not manipulate dom yourself.
Vue 2 retrieves and removes in-dom templates, compiles them to render functions, and render virtual dom back into real dom,
while Vue 1 doesn't remove in-dom templates.
That's a pretty stupid use case I know :)
Since it worked before it could be misleading for people migrating to v2. My use case is pretty specific since I use VueJS on a website using Turbolinks (that reloads the entire body every time a link is pressed) and bind a lots of events everywhere.
Such usage was never documented, and it's obviously a hack, so it wouldn't
be a surprise for most people.
On Fri, Sep 2, 2016, 16:17 Grafikart [email protected] wrote:
That's a pretty stupid use case I know :)
Since it worked before it could be misleading for people migrating to v2.
My use case is pretty specific since I use VueJS on a website using
Turbolinks (that reloads the entire body every time a link is pressed) and
bind a lots of events everywhere.—
You are receiving this because you modified the open/close state.Reply to this email directly, view it on GitHub
https://github.com/vuejs/vue/issues/3587#issuecomment-244312649, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AFTLl0SHGGk7LPlXEsVD5hbQEpeNaTXBks5ql9u3gaJpZM4JzdEX
.
Thanks ! I'll VueJS all my code :)
what if you're in the process of trying to migrate to vue, but you have some legacy parts in jquery
trying to move to vue now means an all or nothing approach
this bit me trying out my first vue component amongst my legacy components
so what you're saying is that I have to move all of them to vuejs and there is no way to intermingle?
Lucky there is a work around. For anyone else who finds this an easy way to get around it is to attach your listeners when vue mounts your element.
mounted: function () {
addHandlers(this.$el);
},
Vue has created $el in the shadow dom but handlers still work if you do it after mounted.
@oppianmatt Could you share a clearer example, I can't tell from the api documentation how best to go about this. I'm currently trying:
var addHandlers = function (el) {
var button = el.getElementByIdName('tooltip-item')
button.addEventListener('click', function (event) {
console.log('clicked ' + event.target)
...
})
}
}
new Vue({
el: '#app',
template: '<App/>',
components: { App },
mounted: function () {
addHandlers(this.$el)
}
})
If anyone with better know-how comes across this, please indicate if this approach to event handling is even possible with Vue
I got this to work by moving the script tag for my pre-existing DOM scripts to be AFTER the vuejs app code.
@squarenomad in your case why aren't you just using @click
for the vue handling of a click?
This post was more for legacy js scripts for people who are migrating to vue but with a big codebase of libraries.
But yeah as @sroberson pointed out, attaching your handlers after vuejs has created it's shadow dom works. Whether that's just putting your script tags after (but then your code has to run synchronous), or by attaching your handlers in mounted
.
Vue takes over the dom so handlers set before vue has taken over are going to be lost (or strange effects). Also can't really modify the dom elements that vue owns
The same thing with select2, if i use Vue.js in a page with Select2 it disables select2 events. How to reenable them?
The wonderful VueJS guide has an example how to wrap an existing js module, and the example they use is select2! https://vuejs.org/v2/examples/select2.html
It uses the very same technique in here by attaching to $el in the mounted stage.
Hello world example is always simple, but the real world is cruel. I cannot init select2 by using vue.js. Select2 is inited by 3rd party framework.
I met the same problem.
I added an onsubmit listener into form before the form was bound to Vue.
But the onsubmit listener got lost.
Any solutions?
I am trying to migrate legacy jQuery plugins / bootstrap plugins and Knockout.js code to Vue.js and this removal of original event handlers by .$mount() is a huge pain. Had absolutely no single problem with plugins / events set in Knockout.js, it supports mix of manual event / dom changes and viewmodel DOM / event changes perfectly. Vue.js 2 decision is very strange - it would be correct in case everyone lived in ideal world where the projects are created from scratch, do not depend on external libs and never refactored. Otherwise it's very user unfriendly approach.
Is it possible for virtual DOM to include (save / restore) original event handlers as well? At least optionally. Also for existing DOM re-compiling it during .$mount() it is probably an unnecessary step.
@StevenWung, @Dmitri-Sintsov i met the same problem, when migrating from jQuery (i am undestand your pain :D). As a temporary solution, you may mount Vue.js into small containers, until all your page will be rewritten on Vue. Or just try to mount Vue instance before other js scipts
met the same problem, when migrating from jQuery
But yeah as @sroberson pointed out, attaching your handlers after vuejs has created it's shadow dom works. Whether that's just putting your script tags after (but then your code has to run synchronous), or by attaching your handlers in mounted.
Funny, I face the use case migrating kinda from Vue to somethinig. In fact, from Vue to Vue with jQuery on top.
The use case is:
To fix this I use the workaround here.
I assign non-Vue event listener after some timeout assuming that Vue has finished repacing its part of the DOM by the time timeout is ended. This way the listener is landed onto the DOM already rendered by Vue.
This should be done in JS module loaded after the Vue code is loaded. Like in last <script>
tag after Vue-containing bundles are loaded.
setTimeout(function () {
document.querySelector('#test-button').addEventListener('click', function(e) {
console.log('Click event worked');
});;
}, 3000);
I know this is coarse. It especially could be coarse on slower devices and networks. So the timeout value should be tested on the real device before implementing this in production. But so far nothing better comes to mind for this use case.
I'm not integrating a legacy system - or upgrading from v1 to v2, but my use case is just a simple example in Codepen. I'm working through some exercises to explain Vue / in which I first show how we would complete the example with plain JS - and then with Vue to talk about the differences - and they can't coexist without following some rules. Example. Where you can't have your standard event listeners described before the new Vue instance. So, I'm showing these people how to do these super simple solutions and everything just _does not work_ with no explanation. I didn't see a 'gotcha' section in the docks / but I'll help make one. I guess it makes sense that anything in the el/Vue context is going to get blown out and replaced - so, no event bound elements should exist in there. Is there a spot in the docs that talks about it?
There are no warnings or errors for so many simple cases I'm running into. Another example, is that you might set up an instance, and then create some components for that instance, but you have to register your components _before_ you create a new instance. Which makes sense if you break it down - but feels a little unexpected and has no error: example
I'm new to Vue.js and I stumbled upon this issue in a project where we want to migrate from jquery to Vue incrementally. After a week of try and error I finally found this issue on Github. So I put the Vue code above the old jquery code and finally everything works. :tada:
This behavior should be definitely in the docs, maybe somewhere at the beginning.
If you're having this problem with Material Design Lite (like I'm having with textfields, causing overlapping text) heres how to solve it:
Add a "mounted" function and inside that function call "componentHandler.upgradeDom()".
E.g. for my TypeScript app (https://github.com/insprintorob/libre) with class based components:
declare var componentHandler : any;
private mounted() {
componentHandler.upgradeDom();
}
Done.
So much effort is spent by various frameworks to implement and to use virtual DOM but in modern browsers it makes the very little speed difference while adding the pain to maintain the second-party components compatibility.
Maybe a good idea would be to have the configuration setting to turn off virtual DOM usage by the framework completely (it could be "on" by default, of course). Such as disabling of interpolation, which is very useful to avoid the conflicts with server-side Jinja2 templates, it is already possible.
I need different functions for body onlick event handler. How to do this in Vue js? Isn't body same thing for all pages? Then I can set only 1 function. But I need different scripts on all pages, for same shared object like body.
I arrived here because event listeners added through Optimize would disappear
First I fixed it by adding v-on
attributes but then changing to another page or reloading would make the event fail (as code is now added after Vue has loaded)
My final solution was to add both v-on
and addEventListener
. The event will not be fired twice as, if one listener exists, the other one doesn't
in my case, using webpack, sb-admin-2, and vuejs. I had to defer the loading of the scripts for sb-admin-2 for it to work properly(sidebar expand/collapse)
in my app.js/main.js where I instantiate the main VueJs app, I use require inside the mounted()
import '../Common/main';
import Vue from 'vue';
new Vue({
el: '#wrapper',
mixins: mixinArray,
mounted() {
require('startbootstrap-sb-admin-2/vendor/bootstrap/js/bootstrap.bundle');
require('startbootstrap-sb-admin-2/vendor/jquery-easing/jquery.easing');
require('startbootstrap-sb-admin-2/js/sb-admin-2');
},
methods: {
}
});
Hope this helps as I was on the same pain with the others, pulled some hair from here and there,
just trying to migrate a jquery based app to vuejs. >,,<
Most helpful comment
what if you're in the process of trying to migrate to vue, but you have some legacy parts in jquery
trying to move to vue now means an all or nothing approach
this bit me trying out my first vue component amongst my legacy components
so what you're saying is that I have to move all of them to vuejs and there is no way to intermingle?