Angularjs & Google Analytics Integration - angularjs

I'm using AngularJS UI Router, and revolunet/angular-google-analytics
https://github.com/revolunet/angular-google-analytics
Here it is my config:
.config(function(AnalyticsProvider) {
// initial configuration
AnalyticsProvider.setAccount('UA-XXXXXXX-X');
// track all routes/states (or not)
AnalyticsProvider.trackPages(true);
// Use analytics.js instead of ga.js
AnalyticsProvider.useAnalytics(true);
// change page event name
AnalyticsProvider.setPageEvent('$stateChangeSuccess');
}))
Now is there any other steps to complete? I have NOT modified any states/controllers to include any analytics code, is there anything else required? And what does the following comment means? I guess enabling 'trackPages' is enough, am I right?
.run(function(Analytics) {
// In case you are relying on automatic page tracking, you need to inject Analytics
// at least once in your application (for example in the main run() block)
})

Official reply from #revolunet
https://github.com/revolunet/angular-google-analytics/issues/35
You can check if it works in the chrome network console. check calls
to google. (via an image i guess)
About the Analytics you need to inject it manually at least once
somewhere in your app. (the run block is the good place) so it can be
instantiated by angular.

Related

Setting Google Tag Manager consent with react-gtm-module

In my React SPA, I use npm module react-gtm-module to connect it to GTM. I can send events, using this syntax:
window.dataLayer.push({
event: 'calc_price_btn'
})
but I am not sure if and how I can send consent updates. Is it possible with this module, or will I have to use the standard gtag HTML snippet? Can react-gtm-module do everything that standard gtag() calls can?
What I was missing was defining the gtag() function:
window.gtag = function(){
window.dataLayer.push(arguments)
}
It confused me that the Google documentation did not include the dataLayer.push() calls—only the gtag() calls. After defining the function, the code snippets from the docs can be used right away.
You don't really have to do anything special programming-wise.
It'll be more of a configuration in GTM.
There are many community templates that manages this, but I would go with Simo Ahava's https://www.simoahava.com/custom-templates/consent-mode/
Just search for it when adding a new tag in GTM.
Then you'll be able to push to the datalayer with certain events with the update, shown in the image below.

Render app dynamically based on the context

I'm developing a react application that will be slighty different in different situations.
The app will be used on third party web services as plugin loaded in an iframe. In this case I must know who request the app because:
I must rebrand (load a different css)
Disable or enable different services.
Moreover the app will be used as our service and in this case must load the default configuration with our brand and all the services.
I'm wondering how to do that. The simplest things that came in my mind is use the localStorage and save a setting variable just before load the iFrame and in the react app I can use the localStorage to understand what to do. Is this a reliable solution?
Also, the iFrame load the website using a request, maybe I can pass a query parameter and set the style and some other values based on that.
Not sure which is the best way to do that.
You can also set cookies based on who is going to use it, see https://www.npmjs.com/package/universal-cookie, but make sure to have the secure flag switched on.
An example, this is client side
import Cookies from 'universal-cookie';
const cookies = new Cookies();
cookies.set('requestedParty', 'Google', { path: '/' });
console.log(cookies.get('requestedParty'));

Passport.js, Express.js, and Angular.js routing: how can they coexist?

I apologize this question turned out a bit long, but I have worked on this for some time and really needed to explain all the story.
Background: App based on MEAN stack, trying to authorize Facebook logins using Passport.js.
Following Passport.js guide I implemented something similar to:
// HTML
Add a Facebook login
// send to facebook to do the authentication
app.get('/connect/facebook',isLoggedIn, passport.authorize('facebook',
{ scope : 'email' })
);
// handle the callback after facebook has authorized the user
app.get('/connect/facebook/callback',
passport.authorize('facebook', {
successRedirect : '/profile',
failureRedirect : '/profile'
}));
Notice the target=_self in the html in order to skip Angular routing.
Clearly, authorization works fine. However, redirection does not work, as the routing is handled by Angular. After authorization I never land on /profile (but on the default Angular route).
Therefore, I tried with a custom callback as suggested by Passport.js here, with the hope of passing json data to Angular, and let Angular do the routing. I ended up doing something like:
// In the controller
$http.get("/connect/facebook").success(function(data){
// here I wait for json data from the server and do the routing
});
// I call this route from Angular
app.get('/connect/facebook',isLoggedIn,passport.authorize('facebook',
{ scope : 'email' })
);
// But Facebook lands here!
app.get('/connect/facebook/callback',function(req, res, next) {
passport.authorize('facebook', function(err, user, info) {
res.json({something:smtg});
...
Clearly custom callbacks work for local-login, as Passport.js explains. But here do you see the problem? I call /connect/facebook from Angular, but I should receive some json from /connect/facebook/callback.
I am about to give up Passport, but before this, do you see any solution which would allow landing on /profile after FB authorization, perhaps with a custom message? Many thanks for reading through.
EDIT:
The same question had been reported as an issue on the Passport-Facebook GitHub account. Some additional attempts have been posted there, but not quite the fix yet.
This is a bit more in depth than can be described in one answer, but I'll try to start pointing you in the right direction.
Essentially, Angular.js routes are not really HTML routes at all, but an internal route structure that happens to use the URL for use of the end user. Remember that Angular.js is a client script, and that a full page reload is not desired, as this will reload the entire script. Therefore, /# is used to trick the browser into jumping to a specific bit of code within the already loaded script. (as opposed to the traditional anchor location in the HTML document). Unfortunately (or fortunately), HTML 5 mode allows you to hide the /# part of the url, so instead of seeing http://somesite.com/#/someroute you just see http://somesite.com/someroute. Rest assured, however, that the /# is still there. Angular.js uses the HTML5 pushState (AKA HistoryAPI) to perform the magic replacement.
Given this, if you have called a server route, you are outside the Angular.js script, and any call to load the angular script again will start from the very beginning. You can't actually call your Angular.js route from the server without a full reload. Therefore, you are really doing a double route redirect here. Your server should be calling it's default route for angular, appending /#/someroute to the call. The angular.js page will load, parse off the /#, and redirect to the correct angular route. Keep in mind, however, that if there was any dependency on already loaded objects, those are no longer in memory. Therefore, any route accessed this way should operate as if it is an entry point to your application.
Effectively, you should try using successRedirect : '#/profile', keeping in mind that the profile route in angular should be treated as an app entry point.
Hopefully this gets you started.
If #Claies's way is not working, is it possible you have not get rid of the #= fragment from the facebook callback.
Have a read of this post

Angular Protractor test session persistence

I'm working on e2e tests for a web app and I would like to log in a user and persist their session.
Specifically the following scenario:
The log in form is posted with valid credentials.
Angular routes the user to a landing page.
I call browser.get( /* the current url */ )
I expect the current URL to be the same, instead of my user getting kicked back to the log in screen.
We're using HTTP header based auth and I don't know how to configure this scenario for testing purposes.
Is it as simple as activating cookies somewhere? Or maybe supporting the auth headers via a config?
I managed to solve this be simply adding browser.sleep(1000) in before calling browser.get( /* the current url */ ).
Basically Protractor was hammering on the router to fast and my app was kicking me out before auth creds were set. Or, perhaps, might be the HTML5 routing takes a little time to process (our deep links are hashed, but then angular converts the hash to HTML5 routes).
You can use browser.waitForAngular(); too.
You can use promises like this
goAfterLogin: function(){
browser.get('http://www.example.com').then(function(){
return this; //or other return
}).then(function(){
return this;
});
}
Its up to you how will you use it (you as well can create promis with waitForAngular() )

Loading constants from a web-service without using resolve or manually bootstrapping the app

I am working on a small piece of an angular project and need to define some constants that are derived from values in a database. I have a REST endpoint that delivers the data I need, but I can't figure out how to load the values before the app gets automatically bootstrapped.
I cannot modify the application to a manual-bootstrapping process. Typically a resolve would be used upon navigation, but I have other components (like modals) that use the constants that aren't necessarily part of any route.
What would be ideal would be some sort of "resolve", but at the application layer. I do have the ability to load npm and bower packages, but anything that changes to a 'manual' bootstrapping method isn't allowed.
In that case I can recommend you to use a $rootScope. I don't understand very well your needs, but everything that is stored in $rootScope will be available in all views. Just fill it with your REST service inside the first or main view of your app. Although, it is important to understand that if you refresh you page, the $rootScope will be as well refreshed, this is, all of your REST calls will be launched again. (Navigating inside angular views is NOT refreshing the page unless you ask for it using window.reload() or similar; it is just the same page with a new controller)
To avoid this last behavior (page refresh) you could also use local Storage, which is basically a small amount of memory inside your browser where you can save any data that you want to keep regardless of your page refreshes. I used in one of my projects this library: https://github.com/grevory/angular-local-storage
It was useful for saving permanent stuff until user logs out.
Hope it helps! And sorry if I am answering something not useful for you
Cheers
It seems that the only way to effectively load some values from a service prior to the app starting is to make the service-call to and then manually bootstrap the app. The idea of an app-wide "resolve" doesn't seem to exist.

Resources