Comments (10)
I'm looking for exactly this functionality. It looks like this issue in particular doesn't have any activity though.
@willcosgrove can you share you code here?
Maintainers, any chance of getting this feature added?
from ahoy.js.
It unfortunately takes a fair bit of code to patch it in, but it would be pretty trivial to add into the library itself.
I was only adding this to the trackClicks()
function, not any of the other tracking functions.
trackClicks() looks like this:
trackClicks = function () {
onEvent("click", "a, button, input[type=submit]", function (e) {
let properties = eventProperties.call(this, e);
properties.text = properties.tag == "input" ? this.value : (this.textContent || this.innerText || this.innerHTML).replace(/[\s\r\n]+/g, " ").trim();
properties.href = this.href;
ahoy.track("$click", properties);
})
}
My solution was to modify the onEvent()
function which is responsible for adding the event listener, and firing the provided callback function when a loggable event occurs. So my onEvent function looks like this:
function onEvent(eventName, selector, callback) {
document.addEventListener(eventName, function (e) {
let matchedElement = matchesSelector(e.target, selector);
if (matchedElement && !matchesSelector(matchedElement, "[data-no-track], [data-no-track] *")) {
callback.call(matchedElement, e);
}
});
}
So to patch all of that in, I've got my own ahoy.js file, which imports ahoy
and then modifies the trackClicks()
function on the ahoy object, and re-exports it. Then in my normal application code, I import ahoy
from my ahoy.js file, instead of from the package.
The final ahoy.js file I have looks like this:
let ahoy = require("ahoy.js").default
// Overriding trackClicks() functionality to support not tracking clicks inside
// a [data-no-track] element
function matchesSelector(element, selector) {
let matches = element.matches ||
element.matchesSelector ||
element.mozMatchesSelector ||
element.msMatchesSelector ||
element.oMatchesSelector ||
element.webkitMatchesSelector;
if (matches) {
if (matches.apply(element, [selector])) {
return element;
} else if (element.parentElement) {
return matchesSelector(element.parentElement, selector);
}
return null;
} else {
log("Unable to match");
return null;
}
}
function onEvent(eventName, selector, callback) {
document.addEventListener(eventName, function (e) {
let matchedElement = matchesSelector(e.target, selector);
if (matchedElement && !matchesSelector(matchedElement, "[data-no-track], [data-no-track] *")) {
callback.call(matchedElement, e);
}
});
}
function cleanObject(obj) {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] === null) {
delete obj[key];
}
}
}
return obj;
}
function page() {
return window.location.pathname;
}
function presence(str) {
return (str && str.length > 0) ? str : null;
}
function getClosestSection(element) {
for ( ; element && element !== document; element = element.parentNode) {
if (element.hasAttribute('data-section')) {
return element.getAttribute('data-section');
}
}
return null;
}
function eventProperties() {
return cleanObject({
tag: this.tagName.toLowerCase(),
id: presence(this.id),
"class": presence(this.className),
page: page(),
section: getClosestSection(this)
});
}
ahoy.trackClicks = function () {
onEvent("click", "a, button, input[type=submit]", function (e) {
let properties = eventProperties.call(this, e);
properties.text = properties.tag == "input" ? this.value : (this.textContent || this.innerText || this.innerHTML).replace(/[\s\r\n]+/g, " ").trim();
properties.href = this.href;
ahoy.track("$click", properties);
});
};
export default ahoy
If you also needed to extend this modification for form submissions, it would be pretty straightforward. You could just copy the trackSubmissions() function from the package and redefine it in your ahoy.js file using the new onEvent
defined in that file.
from ahoy.js.
Hey, sorry for the delay. With Ahoy.js 0.3.9+, you can pass a selector to trackClicks
to accomplish this.
ahoy.trackClicks("a:not([data-no-track])")
Edit: The selector for the behavior described in the initial comment should be:
ahoy.trackClicks(":not([data-no-track]) > a:not([data-no-track])")
Edit 2: My bad, this only works for the direct parent element, while the initial comment was for all parents.
from ahoy.js.
Whoa! Thanks so much @ankane. Thanks also to @willcosgrove.
Do you feel like this issue is resolved now @willcosgrove?
from ahoy.js.
It looks like there's not an easy way to constructor a CSS selector that works for all parent elements (at least not that I can figure out) and leads to noisy CSS selectors, so happy to include this functionality if you'd like to submit a PR @willcosgrove. Let's go with data-ahoy-skip
for the name.
from ahoy.js.
@ankane maybe I'm just not seeing it, but couldn't you just drop the direct child operator and get the desired result?
ahoy.trackClicks(":not([data-no-track]) a:not([data-no-track])")
edit: Regardless, you are right that it does lead to some noisy selectors. I would be happy to submit a PR for it. It may take me a couple of days to get to though.
from ahoy.js.
@willcosgrove I tried this out briefly and it stopped tracking for this:
<a href="blah" data-no-track=true>Click me!</a>
But not for
<div data-no-track="true">
<a href="blah">Click me!</a>
</div>
Am I misunderstanding the selector?
I may just end up being okay with the below example for my purposes. Thanks for this thread!
ahoy.trackClicks("a:not([data-no-track])")
from ahoy.js.
Ah, I understand now why that selector doesn't work. It matches too much. Yeah I think this would need to be supported inside ahoy.js so that it can check for data-ahoy-skip
itself. I'll try and work on a PR for this soon.
from ahoy.js.
Is there any desire to also support the inverse operation? Enabling tracking nested under a certain data attribute? data-ahoy
to turn it back on? Or just combine the two into a boolean data-ahoy="true"
or data-ahoy="false"
which matches how Turbo enables and disables its functionality.
It wouldn't be a much more complicated implementation. Just check the matched element for its closest("[data-ahoy]")
(which can potentially be itself), and if one is found return early if that element's dataset.ahoy === "false"
.
from ahoy.js.
Is there any desire to also support the inverse operation? Enabling tracking nested under a certain data attribute?
data-ahoy
to turn it back on? Or just combine the two into a booleandata-ahoy="true"
ordata-ahoy="false"
which matches how Turbo enables and disables its functionality.It wouldn't be a much more complicated implementation. Just check the matched element for its
closest("[data-ahoy]")
(which can potentially be itself), and if one is found return early if that element'sdataset.ahoy === "false"
.
I personally don't have a need for disabling anything but a single link, so I'm fine with the original data-skip-ahoy approach.
I'll let others weigh in, though!
from ahoy.js.
Related Issues (20)
- ahoy.js does not track click events for a-tags that contain HTML tags. Is it intentional? HOT 3
- Click event is duplicated when redirect from A.html to B.html HOT 2
- Add the option to keep the ahoy_visit cookie alive HOT 2
- Why visitsUrl and eventsUrl should use double // on my side HOT 1
- Update the no-jquery branch HOT 1
- TypeError: Illegal invocation HOT 3
- Add debug messaging around sendbeacon HOT 1
- Cross-Origin Read Blocking (CORB) blocked cross-origin response HOT 1
- Why did you remove #trackAll ? (just curious) HOT 2
- [Idea] Remove TailwindCSS classes from "class" attribute in ahoy.js HOT 1
- Open to moving some helper functions to exports?
- [Idea] The ability to update a visit, or be able to start a visit programmatically.
- Next js and ahoy HOT 1
- Expo Support? HOT 2
- Using useBeacon: true results in NS_ERROR_FAILURES on events HOT 1
- [Idea] Extra attributes on clicks HOT 1
- [idea] trackSubmits could include the action url
- [help] NextJS + Ahoy
- Issue with SSR: window is not defined HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ahoy.js.