• Skip to main content
  • Skip to primary sidebar

Web Development Archive

  • Archive
You are here: Home / Archives for Other

Other

VS Code CLI – Open IDE from terminal with code .

Ez a VS Code CLI (shell command) hiánya. Alapból nincs a PATH-ban, ezért nem működik a code ..

Megoldás (gyors, hivatalos)

  1. Nyisd meg a Visual Studio Code-ot
  2. Cmd + Shift + P → Command Palette
  3. Írd be:Shell Command: Install 'code' command in PATH
  4. Enter

Ellenőrzés

Terminalban:

code .

Ha jól ment, megnyitja az aktuális mappát VS Code-ban.


Ha nem működik (ritka eset)

Manuálisan:

export PATH="$PATH:/Applications/Visual Studio Code.app/Contents/Resources/app/bin"

Majd reload:

source ~/.zshrc

Gyors sanity check

which code

Ha ezt adja:

/usr/local/bin/code  vagy  /Applications/Visual Studio Code.app/...

→ rendben vagy.


Ha akarod, adok egy komplett “fresh Mac dev setup” checklistet (Node, nvm, git, brew, stb.), hogy ne fuss bele ilyenekbe később.

Filed Under: Other

Change Apple terminal account name

scutil --set HostName MacBook-Pro
scutil --set LocalHostName MacBook-Pro
scutil --set ComputerName "MacBook-Pro"
exec zsh

Filed Under: Other

Initialize Angular dev environment

Install PrimeNG

npm install primeng @primeuix/themes

Provider

app.config.ts

import { ApplicationConfig } from '@angular/core';
import { providePrimeNG } from 'primeng/config';
import Aura from '@primeuix/themes/aura';

export const appConfig: ApplicationConfig = {
providers: [
providePrimeNG({
theme: {
preset: Aura
}
})
]
};

Filed Under: Other

Display sidebar only on subpage

// src/app/shared/store/store.service.ts
import { computed, Injectable, signal } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class StoreService {
public readonly isSubPage = signal<boolean>(false);


public setIsSubPage(value: boolean): void {
this.isSubPage.set(value);
}
}
 <div class="container">
@if (store.isSubPage()) {
<div class="grid md:grid-cols-[1fr_360px] gap-6">
<main class="bg-surface-card-light dark:bg-primary-900 rounded-2xl p-6 shadow-2xl w-full">
<router-outlet />
</main>
@if (store.isLoading()) {
<p-skeleton height="222px" class="mb-2" />
} @else {
<app-sidebar />
}
</div>
} @else {
<app-news></app-news>
}
</div>

Filed Under: Other

Custom keyboard shortcuts for MacOS

Ez egy nagyon gyakori probléma a magyar Mac-billentyűzeten — mivel a {}, [], +, ~, | stb. karakterek szinte el vannak rejtve a magyar kiosztásban, és sok fejlesztő emiatt váltogat angolra, ami hosszú távon idegesítő.

Megoldás 1: Karabiner-Elements (ajánlott fejlesztőknek)

⌥ + 1 → & 
⌥ + 3 → #
⌥ + l → /
⌥ + é → [
⌥ + á → ]
⌥ + ű → |
⌥ + ó → +
⌥ + ü → -
⌥ + 8 → *
⌥ + - → `
⌥ + , → <
⌥ + . → >

Ez a legmegbízhatóbb és legflexibilisebb módszer, natív szinten működik minden appban (VS Code, Terminal, Chrome, stb.).

1. Telepítés

https://karabiner-elements.pqrs.org/
Töltsd le és engedélyezd a Security & Privacy-ben (System Preferences → Privacy & Security → Input Monitoring + Accessibility).


2. Saját szabály létrehozása

Menj ide:
~/.config/karabiner/assets/complex_modifications/hungarian-dev-layout.json

Ha nincs ilyen fájl, hozd létre.

Tartalom például:

{
"title": "Hungarian Developer Layout (force English output, ISO MacBook, full extended)",
"rules": [
{
"description": "⌥ + őúéáűóüí- → {}[]|+-\\` on Hungarian ISO keyboard",
"manipulators": [
{
"type": "basic",
"from": { "key_code": "open_bracket", "modifiers": { "mandatory": ["option"], "optional": ["any"] } },
"to": [ { "shell_command": "osascript -e 'tell application \"System Events\" to keystroke \"{\"'" } ]
},
{
"type": "basic",
"from": { "key_code": "close_bracket", "modifiers": { "mandatory": ["option"], "optional": ["any"] } },
"to": [ { "shell_command": "osascript -e 'tell application \"System Events\" to keystroke \"}\"'" } ]
},
{
"type": "basic",
"from": { "key_code": "semicolon", "modifiers": { "mandatory": ["option"], "optional": ["any"] } },
"to": [ { "shell_command": "osascript -e 'tell application \"System Events\" to keystroke \"[\"'" } ]
},
{
"type": "basic",
"from": { "key_code": "quote", "modifiers": { "mandatory": ["option"], "optional": ["any"] } },
"to": [ { "shell_command": "osascript -e 'tell application \"System Events\" to keystroke \"]\"'" } ]
},
{
"type": "basic",
"from": { "key_code": "backslash", "modifiers": { "mandatory": ["option"], "optional": ["any"] } },
"to": [ { "shell_command": "osascript -e 'tell application \"System Events\" to keystroke \"|\"'" } ]
},
{
"type": "basic",
"from": { "key_code": "equal_sign", "modifiers": { "mandatory": ["option"], "optional": ["any"] } },
"to": [ { "shell_command": "osascript -e 'tell application \"System Events\" to keystroke \"+\"'" } ]
},
{
"type": "basic",
"from": { "key_code": "hyphen", "modifiers": { "mandatory": ["option"], "optional": ["any"] } },
"to": [ { "shell_command": "osascript -e 'tell application \"System Events\" to keystroke \"-\"'" } ]
},
{
"type": "basic",
"from": { "key_code": "i", "modifiers": { "mandatory": ["option"], "optional": ["any"] } },
"to": [ { "shell_command": "osascript -e 'tell application \"System Events\" to keystroke \"\\\\\"'" } ]
},
{
"type": "basic",
"from": { "key_code": "slash", "modifiers": { "mandatory": ["option"], "optional": ["any"] } },
"to": [ { "shell_command": "osascript -e 'tell application \"System Events\" to keystroke \"`\"'" } ]
},
{
"type": "basic",
"from": { "key_code": "comma", "modifiers": { "mandatory": ["option"], "optional": ["any"] } },
"to": [ { "shell_command": "osascript -e 'tell application \"System Events\" to keystroke \"<\"'" } ]
},
{
"type": "basic",
"from": { "key_code": "period", "modifiers": { "mandatory": ["option"], "optional": ["any"] } },
"to": [ { "shell_command": "osascript -e 'tell application \"System Events\" to keystroke \">\"'" } ]
},
{
"type": "basic",
"from": { "key_code": "3", "modifiers": { "mandatory": ["option"], "optional": ["any"] } },
"to": [ { "shell_command": "osascript -e 'tell application \"System Events\" to keystroke \"#\"'" } ]
},
{
"type": "basic",
"from": { "key_code": "l", "modifiers": { "mandatory": ["option"], "optional": ["any"] } },
"to": [ { "shell_command": "osascript -e 'tell application \"System Events\" to keystroke \"/\"'" } ]
},
{
"type": "basic",
"from": { "key_code": "8", "modifiers": { "mandatory": ["option"], "optional": ["any"] } },
"to": [ { "shell_command": "osascript -e 'tell application \"System Events\" to keystroke \"*\"'" } ]
}
]
}
]
}

Filed Under: Other

PrimeNG Skeleton

store.service

public isLoading = {
top10TopicGroup: signal<boolean>(false),
trendingTopicGroup: signal<boolean>(false),
freshAndHotTopicGroup: signal<boolean>(false),
portfolioTopicGroups: signal<boolean>(false),
preferredArticles: signal<boolean>(false)
};

// Ha bármelyik tölt, ez true
public readonly loadingSignals: Signal<boolean>[] = [
this.isLoading.top10TopicGroup,
this.isLoading.trendingTopicGroup,
this.isLoading.freshAndHotTopicGroup,
this.isLoading.portfolioTopicGroups,
this.isLoading.preferredArticles
];

public readonly isLoadingAny = computed(() => this.loadingSignals.some((s) => s()));

Child Template

@if (loading()) {
<p-skeleton width="650px" height="32px" borderRadius="8px" />
<p-skeleton width="150px" height="24px" borderRadius="6px" />
} @else {
Real content
}

Child Component

public readonly loading = input<boolean>(false);

Parent Component

public mainStoreService = inject(MainStoreService);

Parent Template

@let loading = mainStoreService.isLoading;
<app-topbar [loading]="mainStoreService.isLoadingAny()"></app-topbar>

Filed Under: Other

trackByIndex

A trackByIndex metódus egy optimalizációs segédfüggvény az Angular @for/*ngFor direktívához, amely azt mondja meg Angularnak, hogyan azonosítsa az elemeket egy tömbön belüli ismétlődő megjelenítéskor.


🔧 Az általad használt változat:

public trackByIndex(index: number, _file: File): number {
  return index;
}

Ez azt jelenti: használja az index-et (sorszámot) az elem egyedi azonosítására.


🧠 Miért fontos ez?

Amikor Angular újrarendereli a DOM-ot (pl. új fájlok feltöltésekor vagy törléskor), akkor:

  • Ha nem adsz meg trackBy függvényt, akkor Angular minden elemet újra létrehoz a DOM-ban, még azokat is, amik nem változtak.
  • Ha használod a trackBy-t, Angular csak azokat az elemeket cseréli ki, amik valóban megváltoztak, így:
    • gyorsabb a DOM frissítés,
    • kevesebb új objektum jön létre,
    • csökkenhet a memóriahasználat,
    • megmaradnak a meglévő DOM állapotok (pl. fókusz, scroll).

📦 Példa sablonban:

@for (file of uploadedFiles; track trackByIndex($index, file)) {
  <li>{{ file.name }}</li>
}

Itt az uploadedFiles tömb elemeit rendereli, és a trackByIndex segíti az Angularnak felismerni, hogy melyik elem melyik.


⚠️ Mikor nem ideális az index használata?

Ha a tömb tartalma gyakran változik (pl. elemek beszúrása/törlése), akkor az index alapú azonosítás pontatlanná válhat. Ilyenkor jobb az egyedi azonosító (id, name, stb.) alapján track-elni:

public trackByFileName(_index: number, file: File): string {
  return file.name;
}

És:

@for (file of uploadedFiles; track trackByFileName($index, file)) { ... }

Ez stabilabb, ha a file.name egyedi.


✅ Összefoglalás

KérdésVálasz
Mit csinál trackByIndex?Segít Angularnak azonosítani a tömb elemeit index alapján
Mire jó?Gyorsabb, hatékonyabb DOM frissítés
Mikor használd?Ha van ismétlődő megjelenítés (@for vagy *ngFor)
Mikor használj mást, pl. file.name?Ha az index nem stabil (pl. lista dinamikusan változik)

Ha szeretnéd, átírhatom az index alapút fájlnévre (file.name)-alapúra.

Filed Under: Other

Localized Route

component

import { LocalizeRoutePipe } from '../../shared/pipes/localize-route.pipe';

@Component({
selector: 'app-home',
imports: [RouterModule, LocalizeRoutePipe],
templateUrl: './home.component.html',
styleUrl: './home.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush
})

template

[routerLink]="['profile'] | appLocalizeRoute"

[routerLink]="['/'].concat(['knowledge-base'] | appLocalizeRoute)"

localized-routes.ts

export const localizedRoutes: Record<string, Record<string, string>> = {
hu: {
home: 'kezdolap',
'knowledge-base': 'tudasbazis',
upload: 'feltoltes',
'not-found': 'nem-talalhato',
error: 'hiba'
}
};

onClick method, ha a többi nem működik

providers: [LocalizeRoutePipe]
...
private readonly _router = inject(Router);
private readonly _translocoService = inject(TranslocoService);
private readonly _localizeRoutePipe = inject(LocalizeRoutePipe);
...
public navigateToProfile(): void {
const lang = this._translocoService.getActiveLang();
const route = this._localizeRoutePipe.transform(['/', lang, 'profile']);
void this._router.navigate(route);
}
<p-button [label]="'SHARED.NEXT' | transloco" (onClick)="navigateToProfile()" />

localized-route.pipe.ts

import { inject, Pipe, PipeTransform } from '@angular/core';

import { LocalizationService } from '@/core/services/localization.service';

@Pipe({
name: 'appLocalizeRoute',
standalone: true
})
export class LocalizeRoutePipe implements PipeTransform {
private readonly _localizationService = inject(LocalizationService);

public transform(routeKeys: string[] | undefined, lang?: string): string[] {
return this._localizationService.localizeRoute(routeKeys, lang);
}
}

localization.service.ts

import 'dayjs/locale/hu';

import { DOCUMENT } from '@angular/common';
import { inject, Injectable } from '@angular/core';
import { Meta } from '@angular/platform-browser';
import { TranslocoService } from '@jsverse/transloco';
import dayjs from 'dayjs';
import { hu } from 'primelocale/js/hu.js';
import { Locale } from 'primelocale/js/locale.js';
import { PrimeNG } from 'primeng/config';
import { combineLatest, Subject, takeUntil } from 'rxjs';

import { localizedRoutes } from '@/localized-routes';

@Injectable({ providedIn: 'root' })
export class LocalizationService {
private readonly _translocoService = inject(TranslocoService);
private readonly _primeng = inject(PrimeNG);
private readonly _meta = inject(Meta);
private readonly _document = inject(DOCUMENT);
private _destroySubject$!: Subject<void>;

public init(destroySubject$: Subject<void>): void {
this._destroySubject$ = destroySubject$;
this._translocoService.langChanges$.pipe(takeUntil(this._destroySubject$)).subscribe((lang) => {
this._setMeta(lang);
this._primeng.setTranslation(this._getPrimengTranslations(lang));
dayjs.locale(lang);
});
}

public localizeRoute(routeKeys: string[] | undefined, lang?: string): string[] {
if (!routeKeys || routeKeys.length === 0) {
return ['/'];
}

const activeLang = lang || this._translocoService.getActiveLang();
return routeKeys.map((key) => {
return localizedRoutes[activeLang]?.[key] ?? key;
});
}

private _setMeta(lang: string): void {
this._document.documentElement.lang = lang;
this._meta.updateTag({ name: 'language', content: lang });

type MetaType = { AUTHOR: string; DESCRIPTION: string; KEYWORDS: string };

combineLatest([this._translocoService.selectTranslateObject('META')]).subscribe(([meta]: [MetaType]) => {
this._meta.updateTag({ name: 'author', content: meta.AUTHOR });
this._meta.updateTag({ name: 'description', content: meta.DESCRIPTION });
this._meta.updateTag({ name: 'keywords', content: meta.KEYWORDS });
});
}

private _getPrimengTranslations(lang: string): Locale {
switch (lang) {
case 'hu':
return hu;
default:
return hu;
}
}
}

Filed Under: Other

Scroll Position Restoration in Angular

app.config.ts

export const appConfig: ApplicationConfig = {
providers: [
provideRouter(
APP_ROUTES,
withViewTransitions(),
withInMemoryScrolling({
scrollPositionRestoration: 'enabled',
}),
),
...

Filed Under: Other

GTM in Angular

environment.ts

import { Environment } from './environment.definitions';

export const environment: Environment = {
googleAnalyticsCode: 'GTM-XXXXXXXX'
};

google-analytics.service.ts

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

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

const GTM_SCRIPT_HEAD = 'gtm-script-head';
const GTM_SCRIPT_BODY = 'gtm-script-body';

@Injectable({
providedIn: 'root'
})
export class GoogleAnalyticsService {
public scriptLoaded = false;

public loadScript(): void {
if (document.getElementById(GTM_SCRIPT_HEAD) || !environment.googleAnalyticsCode) {
return;
}
const gtmScriptHead = document.createElement('script');
gtmScriptHead.id = GTM_SCRIPT_HEAD;
gtmScriptHead.innerHTML = `
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','${environment.googleAnalyticsCode}');
`;
document.head.appendChild(gtmScriptHead);

const gtmScriptBody = document.createElement('noscript');
gtmScriptBody.id = GTM_SCRIPT_BODY;
gtmScriptBody.innerHTML = `
<iframe src="https://www.googletagmanager.com/ns.html?id=${environment.googleAnalyticsCode}"
height="0" width="0" style="display:none;visibility:hidden"></iframe>
`;

document.body.appendChild(gtmScriptBody);

this.scriptLoaded = true;
}

public logEvent(eventName: string, eventParams: Record<string, string>): void {
if (!this.scriptLoaded) {
return;
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
(window as any).dataLayer = (window as any).dataLayer || [];
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
(window as any).dataLayer.push({
event: eventName,
...eventParams
});
}

public removeScript(): void {
this._removeScriptById(GTM_SCRIPT_HEAD);
this._removeScriptById(GTM_SCRIPT_BODY);
this._removeGtmLoaderScript();
this.scriptLoaded = false;
}

private _removeScriptById(scriptId: string): void {
const script = document.getElementById(scriptId);
if (!script) {
return;
}

script.remove();
}

private _removeGtmLoaderScript(): void {
const scripts = document.querySelectorAll('script[src^="https://www.googletagmanager.com/gtm.js"]');
scripts.forEach((script) => script.remove());
}
}

app.component.ts

private readonly _ga = inject(GoogleAnalyticsService);
public ngOnInit(): void {
this._ga.loadScript();
...

Filed Under: Other

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

Primary Sidebar

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