-
Notifications
You must be signed in to change notification settings - Fork 171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New delegate API for event listener #149
Conversation
I will prepare possible usages of this new api on a branch to make sure I can push commits based on feedback to the master branch. |
It is always good to step back for a moment when building a new feature and consider whether it is worth maintaining backwards compatibility. The ideal is that we move the library into an eventing model where extension functions are part of the documentation instead of there being multiple implementations embedded in the core library. A user can then extend through configuration and recipes. To make the code cleaner, what if the
It should probably be renamed to: |
That would mean a little more refactoring. Especially since In addition to that I just wanted to extend this by opening the API to 'advanced users'. The first commit was only to demonstrate new API while maintaining full compatibility and unit test compliance. |
I added support for setting custom version of This has neither the flexibility nor the professionalism of your approach but it keeps the library simple and even though the code grows it remains maintainable. |
|
||
// Custom route tracking function | ||
this.trackRouteFunction = function(trackingFunction) { | ||
trackRouteFn = trackingFunction; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check that trackingFunction
is actually a function before assigning it. No need to throw an error if it is not, just don't set trackeRouteFn.
Ok, so I replaced Right now I am trying to think of a nice API to pass AnalyticsProvider.trackRouteFunction(function(_that) {
// Some scope call
_that.trackPage();
}); However this won't work because the whole idea was to provide a function that matches the event signature. Any ideas? |
I think I have an idea how to pass in the interal object for expert users. if (typeof trackRouteFn === 'function') {
// Redirct event to custom function, passing in protected object
eventListener = function () {
var args = Array.prototype.slice.call(arguments);
var newArgs = [ that ].concat(args);
trackRouteFn.apply(null, newArgs);
}
} |
// and those explicitly marked as 'do not track' | ||
if (!$route.current || !$route.current.templateUrl || $route.current.doNotTrack) { | ||
// This section adds different listeners based on the configuration | ||
var eventListener; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be set to null, for good practice.
@Toxantron why not use binding so the if (typeof trackRouteFn === 'function') {
// Redirect event to custom function, passing in protected object
eventListener = function () {
trackRouteFn.apply(that, arguments);
}
} |
Good point. I thought of binding like I feel like this approaches your original proposal. We could even consider moving the other functions to the provider object and passing them back into the setter like so: this.mobileTracker = function(event, state) {
// ...
};
// in user code
AnalyticsProvider.trackRouteFunction(AnalyticsProvider.mobileTracker); I am not sure if it brings any benefit and would unnecessarily break compatibility, but we would have the chance. For now I think we should use the API to cover current requirements and give users to override the behavior if desired. Either in the README or an additional file we could collect FUF (Frequently Used Functions) like the callback from #155. It could also include samples to skip tracking: AnalyticsProvider.trackRouteFunction(function() {
if (userCondition)
this._trackPage();
}); |
// Avoid tracking undefined routes, routes without template (e.g. redirect routes) | ||
// and those explicitly marked as 'do not track' | ||
if (!$route.current || !$route.current.templateUrl || $route.current.doNotTrack) { | ||
return; | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This got 4 space indentation accidentally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Man, indentation is a pain in the ass. Will fix ASAP.
@Toxantron this is looking solid. Are there tests for everything? Can you add one for the "screeName" being sent in hybridMobileSupport case? Last ask, I promise. |
Thanks, but I don't think it is ready to merge just yet. We allready have unit tests for most of it like tracking and route reading. I will add some for the |
@@ -14,6 +14,7 @@ | |||
.provider('Analytics', function () { | |||
var accounts, | |||
analyticsJS = true, | |||
appName, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change this to hybridMobileAppName. That makes it clearly related to hybridMobileSupport and not a generic configuration value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, please expose this value in the configuration property of the return object. All variables are exposed there (near the end of the file). This variable also needs to be listed in the README.md as available under the configuration property.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Toxantron Do you know if it is legal for the appName property to be undefined in the call to GA? |
I see what you are getting at. I think from documentation it stated that |
if (hybridMobileSupport) { | ||
// For mobile devices we need to track a screen rather than a page | ||
eventListener = function (event, state) { | ||
that._send('screenview', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Log the warning inside the eventListener function, if you weren't already thinking of doing that. Do you think it should still make the _send call?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe @josephlaw can answer the question.. He seems to have more experience with the mobile mode. |
My hybrid app temporary use below
|
@josephlaw what would you expect the library to do when appName was not set? Can you tell how google analytics handles it? |
Wrong button. |
If appName not set then the GA do nothing. |
Ok, then we only log exception and not send the call at all. Agreed @justinsa? |
We should allow for any arbitrary optional values to be defined as well: e.g.,
Otherwise this isn't going to be very useful to @josephlaw since he will need to override the behavior anyways. Perhaps instead of mobileAppName the user can provide mobileAppProperties. |
I agree. And then simply copy properties into the call.
|
@justinsa what do you think? |
} | ||
// Create a copy for the tracking function to avoid manipulation during transmission | ||
var args = angular.copy(mobileAppProperties); | ||
args.screenName = state.name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may need to differentiate between ngRoute
and ui-router
here. The sample taken from #145 seems to use ui-router
while our default is ngRoute
.
@justinsa how do we proceed here? |
@Toxantron This is why we should remove these altogether and instead have a cookbook available that examples specific configurations. Only hybrid mobile cares about this and that should be configured by the developer for their specific scenario. If we simplify all the configuration code we have added and move that to a cookbook then support one reasonable default per handler (like ngRoute), this library becomes better. We can also rev the major version so it is clear the change breaks the past. |
You mean moving just the different delegates or the configuration as a whole? Would you mind adding a small sample of what you have in mind? |
So this is what the the event listener API might look like. Feedback welcome.