keen / keen-js

https://keen.io/ JavaScript SDKs. Track users and visualise the results. Demo http://keen.github.io/keen-dataviz.js/
MIT License
578 stars 143 forks source link

Keen.io disrupts <a> link functionality of apps using Vue.js framework #443

Closed funkhouserw closed 6 years ago

funkhouserw commented 6 years ago

Issue:

Keen.io breaks apps using the vue.js web framework by altering how events trigger and propagate.

Expected behavior:

Vue.js lets you use v-on:click="javascript_function()" to attach click handlers. It overrides default event propagation. For <a> links, it will by default ignore href attributes.

This means <a href="#"> and <a href="/some/page" will essentially behave the same way as <a href="javascript:void(0)">, since the event is entirely handled by vue.js. The href is never used.

This is expected behavior, and keen.io ideally should not affect this.

Current behavior:

Once the keen.js script is added to a page using Vue.js, the default behavior of the html links triggers/propagates once again.

Now <a href="#"> behaves differently from <a href="javascript:void(0)"> The href is no longer ignored and triggers as it would with other frameworks, causing the browser to follow the link. This causes page refreshes and scrolling to ids that is not intended by the app.

To reproduce:

Using: http://www.frontenddeveloperlove.com/frontendlove (not an app I control, simply a good example)

1) click around a bit, particularly with the top nav bar. Note that clicking location, speakers, etc, does not refresh the page.

The speaker button has the following properties.

$('.option-31ZV8jH')
<a href=​"/​schedule" class=​"option-31ZV8jH">​Schedule​</a>​

Specifically, note that despite href="/schedule", the page does not refresh when clicked.

2) From the chrome developer console, insert the keen script onto this page using the snippets tab.

3) click location, speakers, etc (the buttons in the header again)

Note that now the page refreshes whereas before it did not.

Here is the script I inserted to replicate this behavior:

!function(name,path,ctx){
  var latest,prev=name!=='Keen'&&window.Keen?window.Keen:false;ctx[name]=ctx[name]||{ready:function(fn){var h=document.getElementsByTagName('head')[0],s=document.createElement('script'),w=window,loaded;s.onload=s.onreadystatechange=function(){if((s.readyState&&!(/^c|loade/.test(s.readyState)))||loaded){return}s.onload=s.onreadystatechange=null;loaded=1;latest=w.Keen;if(prev){w.Keen=prev}else{try{delete w.Keen}catch(e){w.Keen=void 0}}ctx[name]=latest;ctx[name].ready(fn)};s.async=1;s.src=path;h.parentNode.insertBefore(s,h)}}
}('Keen','https://d26b395fwzu5fz.cloudfront.net/keen-tracking-1.4.0.min.js',this);

Keen.ready(function(){

  var client = new Keen({
    projectId: '<REDACTED>',
    writeKey: '<ALSO REDACTED>'
  });

  client.extendEvents(() => {
    return {
      visitor: { 
        user_id: null
        }
      }
  });
  var options = {
    ignoreDisabledFormFields: false,
    ignoreFormFieldTypes: ['password', 'email'],
    recordClicks: true,
    recordFormSubmits: false,
    recordPageViews: true,
    recordScrollState: true
  };
  client.initAutoTracking(options);
});

A keen problem or a vue.js problem?

I have not investigated the underlying cause of this misinteraction between vue and keen, nor if there is an easy solution for either codebase. Regardless this remains a substantial issue for developers using vue.js who wish to also use keen.io.

There do appear to be temporary solutions on the vue.js side such as manually specifying href="javascript:void(0)" or using <button> elements instead of <a> elements, but these are prohibitively onerous and feel hacky.

Thank you!

adamkasprowicz commented 6 years ago

https://github.com/keen/keen-tracking.js/pull/111

adamkasprowicz commented 6 years ago

@funkhouserw we've published new version of keen-tracking.js (1.4.1) with fixes for bugs like this one. https://www.npmjs.com/package/keen-tracking I've tested new package with Vue/Vue router and everything was working.

funkhouserw commented 6 years ago

Thanks @adamkasprowicz this indeed fixes my issues!