• Skip to main content
  • Skip to primary sidebar

Web Development Archive

  • Archive
You are here: Home / Archives for Angular

Angular

Meta Pixel in Angular

environments.ts

export const environment = {
metaPixelId: '',
};

environment.prod.ts

export const environment = {
metaPixelId: 'XXXXXXXXXXXXXXXX',
};

app.config.ts

import { MetaPixelService } from './services/meta-pixel.service';

export const appConfig: ApplicationConfig = {
providers: [
...
provideAppInitializer(() => inject(MetaPixelService).initialize()),
],
};

index.html

<body itemscope itemtype="http://schema.org/WebPage">
<noscript>
<img
alt=""
height="1"
src="https://www.facebook.com/tr?id=XXXXXXXXXXXXXXXX&ev=PageView&noscript=1"
style="display: none"
width="1"
/>
</noscript>
<app-root></app-root>
</body>

meta-pixel.service.ts

import { DOCUMENT, isPlatformBrowser } from '@angular/common';
import { DestroyRef, Injectable, PLATFORM_ID, inject } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { NavigationEnd, Router } from '@angular/router';
import { filter } from 'rxjs';

import { environment } from '../../environments/environment';

type FbqArguments = [command: string, ...args: unknown[]];

type Fbq = {
(...args: FbqArguments): void;
callMethod?: (...args: FbqArguments) => void;
loaded: boolean;
push: Fbq;
queue: FbqArguments[];
version: string;
};

declare global {
interface Window {
_fbq?: Fbq;
fbq?: Fbq;
}
}

@Injectable({
providedIn: 'root',
})
export class MetaPixelService {
private readonly _destroyRef = inject(DestroyRef);
private readonly _document = inject(DOCUMENT);
private readonly _platformId = inject(PLATFORM_ID);
private readonly _router = inject(Router);

private _initialized = false;
private _lastTrackedHref: string | null = null;

public initialize(): void {
if (this._initialized || !isPlatformBrowser(this._platformId) || !environment.metaPixelId) {
return;
}

this._initialized = true;
this._createFbq();
this._loadPixelScript();

window.fbq?.('init', environment.metaPixelId);
this._trackPageView();

this._router.events
.pipe(
filter((event): event is NavigationEnd => event instanceof NavigationEnd),
takeUntilDestroyed(this._destroyRef),
)
.subscribe(() => this._trackPageView());
}

private _createFbq(): void {
if (window.fbq) {
return;
}

const fbq = ((...args: FbqArguments): void => {
if (fbq.callMethod) {
fbq.callMethod(...args);
return;
}

fbq.queue.push(args);
}) as Fbq;

window.fbq = fbq;

if (!window._fbq) {
window._fbq = fbq;
}

fbq.loaded = true;
fbq.push = fbq;
fbq.queue = [];
fbq.version = '2.0';
}

private _loadPixelScript(): void {
if (this._document.getElementById('meta-pixel-script')) {
return;
}

const script = this._document.createElement('script');
script.async = true;
script.id = 'meta-pixel-script';
script.src = 'https://connect.facebook.net/en_US/fbevents.js';

const firstScript = this._document.getElementsByTagName('script')[0];

if (firstScript?.parentNode) {
firstScript.parentNode.insertBefore(script, firstScript);
return;
}

this._document.head.appendChild(script);
}

private _trackPageView(): void {
const currentHref = this._document.location?.href ?? this._router.url;

if (this._lastTrackedHref === currentHref) {
return;
}

this._lastTrackedHref = currentHref;
window.fbq?.('track', 'PageView');
}
}

Filed Under: Angular

Scroll to ID in Angular

public onScrollToSection_1(): void {
document.getElementById('section-1')?.scrollIntoView({ behavior: 'smooth' });
}
<p-button
class="w-full"
styleClass="w-full"
label="Hogyan működik?"
severity="secondary"
size="large"
[outlined]="false"
(onClick)="onScrollToSection_1()"
/>
</div>
<div id="section-1"></div>

Filed Under: Angular, TypeScript

ScrollToTop on RouterLink

public scrollToTop(): void {
window.scrollTo({ top: 0, behavior: 'smooth' });
}
<a [routerLink]="['/privacy-policy']" (click)="scrollToTop()">Privacy Policy</a>

Filed Under: Angular

Hide something on specific route

V1

private readonly _router = inject(Router);

private readonly _hiddenMastersRoutes = [
'/example-url-1',
'/example-url-2',
'/example-url-3',
] as const;

readonly displayMasters = computed(() => {
const url = this._router.url;

return !this._hiddenMastersRoutes.some((route) => url.includes(route));
});

V2

import { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';
import { Router } from '@angular/router';

@Component({
selector: 'app-sidebar',
templateUrl: './sidebar.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class Sidebar {
private readonly _router = inject(Router);

readonly displayMasters = computed(() => {
const url = this._router.url;

return (
!url.includes('/example-url-1') &&
!url.includes('/example-url-2')
);
});
}
@if (displayMasters()) {
<app-masters />
}

Filed Under: Angular

Redirections in Netlify

npm i -D @netlify/edge-functions
netlify/edge-functions/legacy-category-redirect.ts
import type { Config } from '@netlify/edge-functions';

const MAP: Record<string, string> = {
'/hello-world': '/category/hello-world',
'/sample-post': '/category/sample-post',

};

export default async (request: Request, context: { next: () => Promise<Response> }) => {
const url = new URL(request.url);

// /something/ -> /somethin
const path = url.pathname.replace(/\/+$/, '') || '/';

const target = MAP[path];
if (!target) {
return context.next();
}

url.pathname = target;

return new Response(null, {
status: 301,
headers: {
location: url.toString(),
'x-legacy-redirect': '1', // debug
},
});
};

export const config = {
path: [
'/hello-world',
'/sample-post',
],
};

Filed Under: Angular, Netlify

Pagination Service

Ha a PaginationService providedIn: 'root'-tal singleton, akkor az összes komponens ugyanazt a page signalt fogja használni. Emiatt ha két külön lista is van az oldalon, azok elcsúsznak egymással, mivel közös állapotot használnak.

Megoldás: Komponens szintű provider

pagination-service.ts

import { Injectable, signal, computed, Signal } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class PaginationService {
public page = signal(1);
public perPage = 5;

public setPage(page: number): void {
this.page.set(page);
}

public paginate<T>(data: T[]): Signal<T[]> {
return computed(() => {
const start = (this.page() - 1) * this.perPage;
return data.slice(start, start + this.perPage);
});
}
}

component.ts

export class News {
private readonly paginator = inject(PaginationService);
public readonly paginatedNews = this.paginator.paginate(this.news());

public readonly page = this.paginator.page;
public readonly perPage = this.paginator.perPage;

private scrollToTop(): void {
if (typeof window === 'undefined' || typeof document === 'undefined') {
return;
}

// Kis delay, hogy mobilon is biztosan a végleges layout után fusson
setTimeout(() => {
const anchor = document.getElementById('news-top');
if (anchor) {
anchor.scrollIntoView({
behavior: 'smooth',
block: 'start',
});
} else {
// fallback
window.scrollTo({ top: 0, behavior: 'smooth' });
}
}, 50);
}

public next(): void {
this.paginator.setPage(this.page() + 1);
this.scrollToTop();
}

public prev(): void {
if (this.page() > 1) {
this.paginator.setPage(this.page() - 1);
this.scrollToTop();
}
}
}

template.html

@for (item of paginatedNews(); track item.id) {
<app-card>...</app-card>
}

<div class="flex justify-center items-center gap-4 mt-6 mb-10">
<button
class="dds-button"
[disabled]="page() === 1"
(click)="prev()"
>
Előző
</button>

<span class="dds-text text-lg font-semibold">
{{ page() }}
</span>

<button
class="dds-button"
[disabled]="paginatedNews().length < perPage"
(click)="next()"
>
Következő
</button>
</div>

Filed Under: Angular

DeviceService

import { Injectable, signal } from '@angular/core';

@Injectable({
providedIn: 'root',
})
export class DeviceService {
private readonly mqMobile = window.matchMedia('(max-width: 767px)');
private readonly mqTablet = window.matchMedia('(min-width: 768px) and (max-width: 1023px)');
private readonly mqDesktop = window.matchMedia('(min-width: 1024px)');

public readonly isMobile = signal(this.mqMobile.matches);
public readonly isTablet = signal(this.mqTablet.matches);
public readonly isDesktop = signal(this.mqDesktop.matches);

private readonly mobileListener = (e: MediaQueryListEvent): void => this.isMobile.set(e.matches);
private readonly tabletListener = (e: MediaQueryListEvent): void => this.isTablet.set(e.matches);
private readonly desktopListener = (e: MediaQueryListEvent): void => this.isDesktop.set(e.matches);

public constructor() {
// Listener bekötés
this.mqMobile.addEventListener('change', this.mobileListener);
this.mqTablet.addEventListener('change', this.tabletListener);
this.mqDesktop.addEventListener('change', this.desktopListener);
}
}

Use in component

export class News {
public readonly news = signal(MockNews.data.blocks);

private readonly device = inject(DeviceService);

public readonly isMobile = this.device.isMobile;
public readonly isDesktop = this.device.isDesktop;
}

Use in template

@if (isMobile()) {
mobile
} @else {
desktop
}

Filed Under: Angular

Localize Date Pipe

app.config.ts


import { registerLocaleData } from '@angular/common';
import localeHu from '@angular/common/locales/hu';

registerLocaleData(localeHu);

export const appConfig: ApplicationConfig = {
providers: [
{ provide: LOCALE_ID, useValue: 'hu' },
...
],
};
{{ post.date | date:'y. MMMM d.' }}

Filed Under: Angular

Path mapping in Angular – @ alias

tsconfig.json

{
"compilerOptions": {
"baseUrl": "src",
"paths": {
"@/*": ["src/*"]
}
}
}

Filed Under: Angular

Add custom port to Angular dev server

angular.json
{
"projects": {
"your_project": {
"architect": {
"serve": {
"options": {
"port": 4800
}
}
}
}
}
}
proxy.conf.json
{
"/wp-json": {
"target": "http://cpr.local",
"secure": false,
"changeOrigin": true
}
}

Filed Under: Angular

  • Page 1
  • Page 2
  • Page 3
  • Interim pages omitted …
  • Page 6
  • Go to Next Page »

Primary Sidebar

  • angular.io
© 2026 WP Flames - All Right Reserved