I have an Angular website which I would like to use Google Analytics with to track the page views. Im using Firebase through #angular/fire to host my website. Therefore, I added the #angular/fire library by ng add #angular/fire and enabled the services I needed, plus analytics.
Now according to the docs I can see how one can inject AngularFireAnalytics in their component to log page views:
import { AngularFireAnalytics } from '#angular/fire/compat/analytics';
constructor(analytics: AngularFireAnalytics) {
analytics.logEvent('custom_event', { ... });
}
But Im not able to find a way to only enable the whole analytics only on a specific route, and no where else in the website.
I want to set up different paths for the same LandingPageComponent, so that I can visualize the page views from different advertisement funnels. In general I do not want any means of analytics on any other part of the website except for the page view events related to these URLs that end up in the same component after all.
I managed to solve my question by defining a custom event and adding a condition to check for the specific route that I wanted in the component by injecting Location service from Angular:
import {Component, OnInit} from '#angular/core';
import {Location} from "#angular/common";
import {AngularFireAnalytics} from "#angular/fire/compat/analytics";
#Component({
selector: 'app-xxx',
templateUrl: './xxx.component.html',
styleUrls: ['./xxx.component.scss'],
})
export class XxxComponent implements OnInit {
constructor(readonly location: Location,
readonly analytics: AngularFireAnalytics) { }
ngOnInit(): void {
if (this.location.path() === '/myPath') {
this.analytics.logEvent('custom_event', { ... });
}
}
}
According to what I read, it is not possible to disable the default analytics data collection and instead to just send your custom event. Therefore, you either have to have default data collection enabled and send your custom event, or completely turn analytics off. Although, you can turn on and off the analytics from the component, which I'm not sure if its a good practice.
Please let me know if there is an alternative and better solution.
Related
Background
I'm working on a large application that needs to be upgraded. If I were starting from scratch I'd do this all differently. But right now I need to figure out a fix without touching hundreds of files.
For the same reason, I ideally need this code to work on Nest 6. This project needs to be upgraded to the latest nest, but there are some things that need to be fixed to do this. Before I can do that, I need to resolve the current issue, which is blocking us from upgrading off of node 12
Problem
I have a logger class. This class is supposed to pull in some information from the REQUEST context, if one is available (basically, some headers). If no request context is available, this can be ignored.
For simplicity in talking about this, we can say that I need a provider Logger which returns either a RequestAwareLogger or PlainLogger instance, depending on whether or not it is being resolved from a request scope. Alternately, I need the provider to return the same class, with either a request injected (via #Inject(REQUEST)), or left undefined.
Edit For posterity: If I were writing this from scratch, I'd just update the logger.log call to consume this information directly by passing in the request object, or the fields I needed tracked. But since this is a huge project already, I'd have to modify 1000 lines of code in different files, many of which don't have direct access to the request. This will be a longer term effort
Unfortunately, there is no built-in way to do this in Nest. However, it is possible to create a custom provider that would achieve the same effect.
Here is an example provider that would return either a RequestAwareLogger or PlainLogger instance, depending on whether or not it is being resolved from a request scope:
#Injectable()
export class LoggerProvider {
constructor(
#Optional() #Inject(REQUEST) private readonly request?: Request,
) {}
getLogger(): PlainLogger | RequestAwareLogger {
// If a request is available, return a RequestAwareLogger instance
if (this.request) {
return new RequestAwareLogger(this.request);
}
// Otherwise, return a PlainLogger instance
return new PlainLogger();
}
}
Then, you can use this provider in your logger service like so:
#Injectable()
export class LoggerService {
constructor(private readonly loggerProvider: LoggerProvider) {}
log(message: string) {
const logger = this.loggerProvider.getLogger();
// Use the logger instance
logger.log(message);
}
}
Note that this provider will only work if Nest's IoC container is used to resolve the logger service. If you are using a different IoC container (e.g. in a non-Nest application), you will need to create a custom provider for that container.
I'm new in Angular and I was trying to create my own directive using two options:
Option 1: Direct access to the elements using ElementRef
Option 2: Using the Renderer2
Option 1:
import { Directive, ElementRef, OnInit } from '#angular/core';
#Directive({
selector: '[appBasicHighlight]'
})
export class BasicHighlightDirective implements OnInit {
constructor(private elementRef: ElementRef) {}
ngOnInit() {
this.elementRef.nativeElement.style.backgroundColor = 'green';
}
}
Option 2:
import { Directive, ElementRef, Renderer2, OnInit } from '#angular/core';
#Directive({
selector: '[appBetterHighlight]'
})
export class BetterHighlightDirective {
constructor(private elementRef: ElementRef, private renderer: Renderer2) { }
ngOnInit() {
this.renderer.setStyle(this.elementRef.nativeElement, 'background-color', 'blue');
}
}
The instructor from the tutorial said that it is much safer and recommended to use the Renderer over the direct access but didn't explain explicitly the reasons. He meant direct DOM access by using ElementRef but as you can see from the code, Renderer used ElementRef too. With this, I'm confused on what makes Renderer safer and advantageous over ElementRef.
From angular document
"Permitting direct access to the DOM can make your application more
vulnerable to XSS attacks. Carefully review any use of ElementRef in
your code. For more detail, see the Security Guide."
"Use this API as the last resort when direct access to DOM is needed.
Use templating and data-binding provided by Angular instead.
Alternatively you take a look at Renderer which provides API that can
safely be used even when direct access to native elements is not
supported."
Or another explain when we need to use renderer
The Renderer is a class that is a partial abstraction over the DOM.
Using the Renderer for manipulating the DOM doesn't break server-side
rendering or Web Workers (where direct access to the DOM would break).
The Renderer2 class is an abstraction provided by Angular in the form
of a service that allows to manipulate elements of your app without
having to touch the DOM directly. This is the recommended approach
because it then makes it easier to develop apps that can be rendered
in environments that don’t have DOM access, like on the server, in a
web worker or on native mobile.
So when direct access to native elements is not supported you should use renderer
The author of this tutorial explains why it's a better approach. He says 'because it could be that your application is not running in an environment where it has access to the DOM. Angular also works with ServiceWorkers...'. It's in Angular The Complete Guide (2021 Edition), lesson 94, 5:40
and see:
https://betterprogramming.pub/angular-manipulate-properly-the-dom-with-renderer-16a756508cba
Newbie question:
When working with NestJS and TypeORM, and one has created a custom repository (which extends the standard repository), is a seperate service class needed anymore?
At the moment, I'm working only with the custom Repository class and it works fine, but I'm not sure if this is correct and perhaps has some side effects.
Btw, in another project i have no custom repo, only a service which get's two standard repo's injected, and this works also fine.
Regards,
sagerobert
I think it's up to you how much you want to add layers between typeORM and your most "front-office" code (that would be the controllers in a typical nest application).
I explain myself:
If you want, you could typically inject directly the built-in typeORM repositories into your controllers:
import {Controller, Get} from '#nestjs/common';
import {InjectRepository} from '#nestjs/typeorm';
import {Repository} from 'typeorm';
import {User} from './entities/User.entity';
#Controller()
export class AppController {
constructor(
#InjectRepository(User)
private readonly userRepository: Repository<User>,
) {
}
#Get()
async root(): Promise<User> {
return await this.userRepository.find(1);
}
}
So this would be the less layered implementation of how to retrieve the user with ID = 1.
Now, the documentation of NEST recommends to abstract this repository and inject it into a service rather than in a controller directly. This allows you to have less binding between your controller and TypeORM. Instead, it's your service that has this binding. If you have many controllers that use this repository, and you decide that you want to change TypeORM and use the new fancy ORM, you'll have to change every controller.
Now, if you just inject the repository inside your service and use this service into all your controllers, you will just have to change the implementation of your service and all the controllers will remain the same.
Secondly, imagine that you want to test your application. You will face the same problem. How can you run your tests without an SQL connection? I suppose that your unit tests are not created to test the TypeORM behaviour, but instead written to test YOUR code behavior.
It will be much easier to mock a repository injected in a service than mock all repositories injected in your controllers.
So to conclude this answer, I think that this question should be closed because it is primarily opinion-based. But IMO, the dreamed architecture is the following:
Create a Custom Repository that extends the TypeORM Repository.
Inside the Custom Repository, add methods that use the Query Builder.
Inject this Custom Repository into your services
Inject the services into your controllers.
Don't ever use the query builder into controllers because it is hard to mock.
I hope this answers to your question: A service class is not needed. But it will help you keep your code clean.
First time using Vuejs and have a question about organization. Building a website pages vary in functionality, one page may have many areas of functionality [modals, forms, pagination, content filtering via ajax]. Would it be best to have a new Vue() for each page stacking functionality by components or each section of functionality should have it's own new Vue(). Some of these sections may need to talk to one another. My concern is having a main app.js file that is bloated.
No, you can just use one new Vue() instance for all pages. It does not make sense to have multiple vue instances per page.
As on a page reload the instance is recreated. I guess you don't have a SPA. So you rather have some templates where you have your app container and the vue components there, right?
You can for example create a components/index.js where you import / export all your components. So you have an entry for your components. (Cleaner structure)
And in your main.js you simply import them.
import Vue from 'vue'
import Components from './components/'
const app = new Vue({
components: {...Components }
}).$mount('#app')
And your components.js will look like this
import Pagination from './components/pagination.vue'
import Modal from '.components/modal.vue'
const Components = {
Pagination,
Modal
}
export {...Components }
export default Components
You can then import your components as es6 modules
import {Modal, Pagination} from './components'
Which is a nice way of organizing them if you use them in other components.
However, as you don't use vue-router you can't (at least I don't know any way) use webpacks code splitting to create smaller bundles, depending on their route and components used on that route.
I am writing an application using Angular2 and when it comes to protecting some admin sections of the application, I plan to follow the proposed approach in Angular2's website : https://angular.io/docs/ts/latest/guide/router.html#guards
So I will end up with a class like this one :
#Injectable()
export class AuthGuard implements CanActivate, CanActivateChild {
constructor(private authService: AuthService, private router: Router) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
// Use my service to determine if user is logged in and has credentials
return this.authService.canHaveAccess();
}
}
Once transpiled into JS code and executed on my user's browser, what would prevent a user to redefine the canActivate method so that it bypasses the call to canHaveAccess and instead always returns true ?
Nothing.
If you rely on the code in the users browser for your application to be secure you're doomed.
Security needs to be enforced on the server. In the browser guards are only for the users convenience to not show options and forms that are not relevant for the user but such measures are irrelevant in regard to security.