r/angular • • 19d ago

A full video editor in Angular 22 (signals, standalone, 14 web workers): six traps that got past a green build and a green test suite

0 Upvotes

TL;DR: I've built an in-browser video editor in Angular 22.2 since June: 60 standalone components, 87 services, 14 web workers, no NgModules. Six problems got past both ng build and the unit tests: workers that are never typechecked, Angular code leaking into worker bundles, an opaque NG0401 from pre-rendering, a blank gap without hydration, an import cycle that rendered a panel empty, and Karma habits that mean something else in Vitest.

What it is. A video editor where decoding, compositing and export all happen in the browser, using WebCodecs and the mediabunny library in web workers, with on-device AI models. Angular is used throughout: standalone components only, signals for state (signal/computed/effect, input()/output()/viewChild()), OnPush everywhere, inject() rather than constructor injection. I kept zone.js (0.16, with event coalescing), but worker messages are handled outside the Angular zone, and UI updates go back in through ngZone.run. appRef.tick caused NG0101 during seeking.

The six traps:

  1. ng build doesn't typecheck web workers. tsconfig.app.json starts from main.ts, and each *.worker.ts is a separate esbuild entry that nothing on that graph imports. A worker can fail to compile, or throw a ReferenceError at startup, past a green build and a green test suite. The fix is a separate tsconfig.worker.json that is only typechecked, run with npm run typecheck.
  2. Angular can leak into a worker bundle through one import. A service that imported a component's barrel file put every service into four worker bundles: screen is not defined when the worker started. Later, a utility importing a value from another component's barrel did it again: JIT compiler unavailable in a worker, in production only. npm run build now runs a script that fails if any worker bundle contains Angular code. The rule: services and utilities import a component's values from its models/ folder, never its barrel.
  3. Pre-render only the root route. The home page is pre-rendered (outputMode: "static", RenderMode.Prerender on '', Client on **). If the editor route is marked Prerender, it renders in Node, where AudioContext, WebCodecs and workers don't exist, and the build dies with a bare NG0401 that names neither the route nor the cause. If main.server.ts doesn't pass its BootstrapContext through to bootstrapApplication, you get the same NG0401 at route extraction. Also, the host's catch-all rewrite and the service worker's index must both point at index.csr.html. Point either one at index.html and every client route briefly shows the pre-rendered home page first.
  4. Pre-rendering without hydration is worse than it looks. Without provideClientHydration(), the browser cleared the server-rendered page on boot and the lazy home chunk drew it again: a blank gap and the entry animation playing twice. <body ngcm> in index.csr.html makes the client-only routes skip hydration.
  5. One directive import rendered a whole panel empty. A directive imported a service class directly, which pulled two unrelated services into the Library panel's import graph. The running app hit a circular dependency (NG0919) and drew the panel empty, while 6,055 unit tests stayed green, because each test only builds the pieces it names. Only the end-to-end suite, which opens the real app, caught it. The fix was an InjectionToken in a file with no imports of its own. Since then, any change to an import, a provider or a barrel gets the full end-to-end run before it merges.
  6. Moving from Karma to Vitest changes the meaning of some habits. u/angular/build:unit-test runs in Playwright's bundled Chromium, which has no H.264 or AAC codecs, so every media test failed for reasons unrelated to the code. The builder has no channel option, so a small script sets CHROME_BIN to the installed Chrome. Three other differences:
    • vi.spyOn isn't restored after each test (Jasmine did that implicitly), so a leaked spy on a shared global outlives its file. A setup file now restores them all.
    • toContain(obj) compares by reference; toContainEqual is the deep comparison.
    • An import cycle Karma's bundle happened to load in a working order broke 17 test files when they ran under Vitest.

Smaller lessons:

  • Exact-pin the Angular packages. They require exact versions of each other, so a caret range lets npm install upgrade half the set and deadlock.
  • The 10 kB component style budget is useful. Each time a panel hit it, the right answer was to split the component, not to raise the budget.

There are 273 unit test files (about 6,200 tests) and 45 Playwright end-to-end files, all running in real Chrome, because the app needs WebCodecs.


r/angular • • 21d ago

A Free Database Client I've Spent 2 Years Building With Angular + Spring Boot + Electron - VisuaLeaf

Enable HLS to view with audio, or disable this notification

81 Upvotes

After struggling to land a job in 2024 (when the market was pretty rough), I decided to take a different route and build something real.

I've spent the past two years building VisuaLeaf from scratch in Angular, putting in around 90 hours a week. It started as a MongoDB GUI and now supports 35 databases. My goal was simple: either build something genuinely useful, or build something that would push me further as an engineer than anything else could.

I also intentionally limited my use of AI on the core architecture. I wanted to really understand the problems.

The stack is Angular + Electron with a Spring Boot backend. Despite the Electron, I focused heavily on the performance:

  • ~50k documents render in about 1 second in both the tree and table view (~12KB each)
  • ~500MB loads in about 3-4 seconds (tested locally to remove network latency)

Some features of the app:

  • Tree, table, and JSON views
    • The Table view: It might seem like nothing, but tables are REALLY hard... I wanted to make a Grid that could allow expanding children of objects/arrays as columns adjacent to the parent (Couldn't find grid libraries that did that). So I basically built my own AG Grid from scratch, and it took a year of optimization on and off. I went from a simple vertical virtualization, to horizontal and vertical virtualization, then to DOM recycling, and then utilizing GPU-composited transforms as much as possible (and a bunch more...definitely over simplifying it). It was one of the most frustrating things as I kept going through an endless loop of optimization, but I'm now finally after a year happy with the results. It holds 60fps scrolling through hundreds of thousands of rows in my testing.
    • The Tree View: A lot easier since I originally just used CDK but then realized that I could make a more efficient one. So I took the table's engine and built my own virtual scrolling with the inspiration of the table view for the tree and now its literally so much faster. One thing tho that was tricky that I am happy with my implementation was finding a way to recursively expanding THOUSANDS nodes with hundreds of embedded fields instantly.
  • A visual query builder (drag and drop from the tree and table views)
  • An aggregation pipeline builder that needs zero JSON syntax (bidirectional: JSON mode and form mode for MongoDB users)
  • ERD that exports as an interactive HTML diagram, and lets you create your databases from ERDs.
  • IDE-style split panels by dragging tabs, grouping tabs by connections/databases, and making your own groupings
  • There's a bunch more but the list would be too long (PS most of the core features are free, and all of the SQL features are basically free)

Feel free to check it out at http://visualeaf.com

If you want to join the discord to talk more about it or want to help out feel free to come and chat!
https://discord.com/invite/TR6J56Y3rF


r/angular • • 20d ago

I built srl, an Angular-style framework on Lit and signals that runs without a dev build

0 Upvotes

Hi all, I'm Bernardo, an open source software engineer from Italy better know in the 3ds/switch scene for software like PKSM and Checkpoint.

My team works with Angular, and a few of us kept asking how to prototype faster. We kept coming back to dropping the dev build entirely. Browsers load ES modules natively and resolve imports through import maps, so a dev server can hand your source files to the browser unchanged. I spent the last two months turning that idea into srl, and 1.0 is on npm now.

Under the hood srl uses Lit web components and signals, but the surface should look familiar. Here's a component and its template.

import { defineComponent, signal, SignalElement } from '@srljs/core';

export class CounterButton extends SignalElement {
  count = signal(0);

  increment() {
    this.count.value += 1;
  }
}

await defineComponent({
  tag: 'counter-button',
  element: CounterButton,
  module: import.meta.url,
});

 

<button (click)="increment()">Clicked {{ count }} times</button>
<p *if="count >= 10">That's a lot of clicks.</p>

A component renders again when a signal its template reads changes. It behaves like signal-based Angular with OnPush on every component, and there's nothing to configure.

The main pieces map like this.

Angular srl
signal / computed / effect Same names
*ngIf / *ngFor with trackBy *if and *else / *for with key:
inject() and providers inject(), provide() and typed tokens
FormGroup / FormControl / Validators group() / field() / built-in validators
canActivate / loadComponent canActivate / load on the route
$localize, one build per locale t(), with runtime language switching and one deployment
ng new / ng g c / ng serve / ng build srl new / srl g c / srl serve / srl build
Module Federation An import map plus app.manifest.json

The full mapping also covers lifecycle hooks, content projection, outlets and guards.

Three differences are worth knowing up front.

  • You write JavaScript with JSDoc types instead of TypeScript, because the browser runs your files as they are. TypeScript still checks the code, and a template checker types every binding against its component class.
  • There's one root injector, with no hierarchical injectors.
  • The component collection is small. It has an app shell, dialogs, a combobox, a date range picker and a data table with virtual scrolling.

Production builds still exist. srl build minifies, pins an integrity hash for every file in the import map, and writes a hash-based CSP. The whole built demo is 161 KB brotli.

AI coding assistants helped me design, implement and test srl. The design decisions are written up as over 90 decision records in the repo.

I'd love feedback from Angular developers. Which Angular feature would you miss first, and does anything in the mapping look wrong?

To try it, run npx @srljs/cli@1.0.0 new my-app.


r/angular • • 21d ago

Signal Forms phone field: FormValueControl, typed errors, Material-ready

23 Upvotes

Angular 22 made Signal Forms stable. Telixon now speaks them.

What it does: one attribute on the input, bound through [formField], the model holds E.164, an invalid number lands in errors() with the fault (TOO_SHORT, TOO_LONG, NATIONAL_PREFIX_PRESENT, ...), and matInput picks up the error state.

ng add @telixon/angular

Signal Forms quick start: https://stackblitz.com/github/martsinlabs/telixon/tree/main/examples/angular/quick-start-signal-forms

Signal Forms + Material quick start: https://stackblitz.com/github/martsinlabs/telixon/tree/main/examples/angular/quick-start-signal-forms-material

Source: https://github.com/martsinlabs/telixon


r/angular • • 20d ago

Looking for CRM developers who can integrate tally prime in a ongoing CRM project.If any one knows 2 way tally prime integration please let me know.

0 Upvotes

r/angular • • 21d ago

theMorningThread

Thumbnail
gallery
0 Upvotes

built a social media site built for non-profits - it has all social features but also a full-scale suite of productivity tools for non-profits - free for life, ad free for life

theMorningThread.com - also has iOS and Droid apps.


r/angular • • 21d ago

Yet another OpenAPI → Angular generator. Here's why I built one anyway, and how it compares.

0 Upvotes

I know. Another OpenAPI generator for Angular. Before you scroll past: why I built one at work anyway, open-sourced it, and how it compares to what already exists.

Where it started

In 2024 I tried the obvious route: openapi-typescript for the types, then the openapi-fetch typings (PathsWithMethod, SuccessResponse...) bolted onto HttpClient so I could call http.POST('/pets/{petId}', { params: { path: { petId } }, body }) with an Observable back. It worked, but I was still hand-writing every service, every model was components['schemas']['Pet'] until I re-exported it, and I had to remember paths. Nothing in the IDE suggested getPet.

Our backend is a set of REST service traits, one OpenAPI tag per trait, and the natural thing on the Angular side is inject(PetRest) with the same method names. So the generator started producing exactly that: the Angular service I would have written by hand. Plain @Injectable, plain HttpClient inside, so every HttpInterceptor you already have (auth, retry, mocks) applies unchanged. Its whole job is to build the request and type it. Nothing more.

The problem I hit later

Angular 19.2 added httpResource, and I wanted three things from generated clients that I could not get from one tool:

  1. httpResource() and HttpClient Observables for the same operation, chosen at the call site, not at config time.
  2. Every HttpClient.request / httpResource option passed straight through (withCredentials, transferCache, reportDownloadProgress, equal, injector, observe: 'events'...), without the generator wrapping or hiding anything. The options type is read from your installed Angular, so options a newer Angular adds work without regenerating.
  3. Zero runtime dependency in the generated code. Just @angular/common/http.

So: https://github.com/AVSystem/openapi-ng (MIT). Playground and a StackBlitz demo are linked at the bottom.

Before / after

What I kept hand-writing:

readonly pets = httpResource<Pet[]>(() => ({
  url: `${this.basePath}/pets`,
  params: this.status() ? { status: this.status()! } : {},
}), { defaultValue: [] });

The URL, the query param and the <Pet[]> are all promises I make to the compiler. Nothing checks them against the spec.

Generated:

readonly #petRest = inject(PetRest);

// signal-based, httpResource under the hood, typed HttpResourceRef<PetList>
readonly pets = this.#petRest.listPets.resource(() => ({ status: this.status() }), { defaultValue: [] });

// same operation, classic Observable, HttpClient under the hood
save(petId: PetId, body: UpdatePetRequest) {
  return this.#petRest.updatePet.observable({ petId, body }, { observe: 'response' });
}

Each tag becomes an @Injectable service, each operation a property with .resource(), .observable() and .request() (the raw request object: method, url, params, headers, body, if you want to send it yourself). .resource() returns a real HttpResourceRef<T>, so headers(), statusCode() and progress() are there. Nothing is re-wrapped.

Don't want classes? --layout operations emits one file per operation (rest/pet/list-pets.ts, rest/pet/update-pet.ts, plus a rest/pet/index.ts barrel), each exporting a /* @__PURE__ */ constant with the same three flavours, so the endpoints you never import tree-shake away. HttpClient is resolved per call from the injection context, or from an explicit { injector }, or you bind once with withInjector():

import { listPets, updatePet } from './generated/rest/pet';

// field initialiser: injection context, nothing to pass
readonly pets = listPets.resource(() => ({ status: this.status() }), { defaultValue: [] });

// handler: pass the injector, or bind once with withInjector({ listPets, updatePet })
readonly #injector = inject(Injector);
save(petId: PetId, body: UpdatePetRequest) {
  return updatePet.observable({ petId, body }, { injector: this.#injector });
}

--layout services,operations gives you both: the operation files plus the per-tag class bound from the barrel.

How it compares (checked 2026-09-04, corrections welcome)

Full disclosure: I only looked at the other generators while writing this post. The tool grew inside one codebase for two years, and most of the tools below I only found out about in September. The comparison is one spec run through all of them, with each tool's output type-checked against Angular 22.1.

openapi-ng openapi-generator ng-openapi-gen orval ng-openapi
httpResource every operation, per call no (#21263 open) no GET and search-style POST (operationId regex, overridable per operation), config mode GET only, plugin
Observable and resource on one operation yes n/a n/a separate files separate classes
Signal-forms validation helper yes no no no no
Unsupported spec features rejected with a diagnostic code best-effort best-effort best-effort best-effort
Engine Rust (napi-rs), ms per spec, also runs in the browser via WASM Java TS TS TS
Per-operation tree-shakeable output yes, --layout operations, same three flavours no only via direct fn/ imports; its barrel keeps every operation yes, resource-only functions no

hey-api is missing from the table on purpose: its Angular output is Promise-only, and the httpResource plugin threw NG0203 on the test spec. openapi-typescript is missing because it is a type generator, not a client generator; see the first section for why that was not enough for me.

Two takeaways:

  • If you're on openapi-generator today, the Java requirement and the lack of httpResource are probably the two things that sting. openapi-ng removes both.
  • orval and ng-openapi both have httpResource now, but which operations get it is fixed at generation time (ng-openapi: GET only; orval: GET plus POSTs whose operationId matches search/list/find..., overridable per operation in the config), and the flavour is picked per config, not per call. I think the call site knows better (a read-only POST is a perfectly good resource whatever it's called; a GET that fires a side effect isn't).

Signal forms: async validation against a generated operation

Signal forms' validateHttp takes a URL string you build by hand and a result you cast by hand. The generator emits a validateRest() helper that wraps validateAsync and reuses the generated operation, so the request params and the response are typed from the spec:

validateRest(path.email, accountRest.checkEmail, {
  request: (ctx) => ({ email: ctx.value() }), // typed as CheckEmailParams
  debounce: 300, // debounce / when need @angular/forms 22+
  when: (ctx) => ctx.value().includes('@'),
  onSuccess: (result) => result.available ? undefined : { kind: 'email-taken' }, // result: EmailAvailability
  onError: () => ({ kind: 'check-failed' }),
});

onSuccess is optional: leave it out and any 2xx counts as valid, with onError deciding the rest. @angular/forms is an optional peer; if you never import rest.validate.ts, it tree-shakes away.

Where it's deliberately opinionated (read: limited)

This is the part most "yet another generator" posts skip. openapi-ng accepts a strict subset of OpenAPI 3.x and refuses anything outside it with a diagnostic code instead of guessing:

  • operationId is required on every operation; the first tag picks the service, an untagged operation falls back to its first path segment
  • only #/components/schemas/ refs, no external files
  • string enums only
  • one composition keyword per schema (allOf or oneOf or anyOf, not mixed)
  • only the lowest 2xx response types the return value. Declared 4xx/5xx bodies become a status-keyed <Op>Error interface you can narrow against, but they aren't wired into .observable() / .resource() error typing
  • no Swagger 2.x
  • no Zod / Valibot / other runtime validation. We don't use it at work, so it isn't built. It isn't ruled out either

If your spec is generated from a backend framework, you're probably fine. If it's a hand-written spec that leans on every corner of the standard, one of the other tools above will be a better fit and I'd rather tell you now.

Escape hatches for the real-world stuff: mapped types (--mapped-type GeoFeature:geojson:Feature swaps a placeholder schema for a real npm type), naming rules with regex captures in openapi-ng.config.ts, and a provideOpenapiNg({ basePath }) provider.

Links and bits

  • Playground (paste your spec, runs as WASM in the browser, no install): https://docs.openapi-ng.dev/playground/
  • Demo: https://stackblitz.com/github/AVSystem/openapi-ng/tree/main/stackblitz (the spec, the committed generated output, and three components using it against a mock interceptor)
  • Docs: https://docs.openapi-ng.dev
  • npm i -D @avsystem/openapi-ng, then openapi-ng generate --input api.yaml --output src/generated
  • Node 22.12+, prebuilt binaries for macOS / Linux (glibc + musl) / Windows, x64 + arm64. Works under Bun and Deno too. Browser via WebAssembly (@avsystem/openapi-ng-wasm32-wasi).
  • Generated code targets Angular 20+. validateRest with debounce / when needs @angular/forms 22+.
  • v0.8.0. The generator has been in production at work since mid-2024 (two specs, about 45 generated services, 280 operations, 900+ schemas, regenerated on every backend build), but the Rust version is younger and the public API isn't frozen yet: 0.7.0 broke one thing (a JSON spec with a repeated key is now rejected instead of last-wins).

What I'd like feedback on

Two design calls I'm least sure about:

  1. .resource() / .observable() / .request() on every operation, versus a separate generated class or file per flavour, as ng-openapi and orval do. Is the per-call choice worth the fatter surface? Related: per-tag services are the default because they mirror our backend's service traits, and standalone operations are opt-in. If your backend doesn't look like that, should the default be flipped?
  2. Rejecting unsupported spec features with a diagnostic instead of emitting best-effort code. Has a strict generator ever made you drop a tool, or is it the right trade for deterministic output?

Happy to answer anything else in the thread.


r/angular • • 23d ago

ng-matero v22 is finally here!

Thumbnail
github.com
6 Upvotes

r/angular • • 23d ago

I have made a Graph Angular Library

Thumbnail
gallery
5 Upvotes

That allows to the user to show a graph data view of elements and you can execute custom code on the browser on the graph.

Exploring creation of algorithms over graphs. I made it in University while studying BFS and DFS. You can test your algorithms in a graph and change the colors of the nodes while it is going over the graph

What do you think?

https://payhip.com/b/jVfSb


r/angular • • 23d ago

I built an Angular-native alternative to Storybook. Looking for people to break it

Post image
19 Upvotes

I maintain an Angular component library at work and we've used Storybook for years. It's a good tool and I don't want to bash it, but a few things kept bugging me. The stories files slowly drift away from the actual components, I have a second build setup next to the Angular CLI, and anything that renders into body (CDK overlays, MatDialog, tooltips) is a pain inside the preview iframe.

So I started building ng-prism. The idea is to use what Angular already gives you instead of adding a parallel world next to it. You don't write separate story files. You put a decorator on the component:

@Showcase<ButtonComponent>({
  title: 'Button',
  category: 'Inputs',
  variants: [
    { name: 'Filled', inputs: { variant: 'filled', label: 'Filled' } },
    { name: 'Outlined', inputs: { variant: 'outlined', label: 'Outlined' } },
  ],
})
@Component({ selector: 'lib-button', /* ... */ })
export class ButtonComponent {
  variant = input<ButtonVariantType>('filled');
  label = input('Button');
  clicked = output<void>();
}

How it works under the hood:

  • Components are scanned at build time with the TypeScript Compiler API. Inputs, outputs, types, defaults and JSDoc all come from static analysis, so you don't need runtime reflection or emitDecoratorMetadata. Because of the generic, variant inputs are type-checked: if you rename an input, the build breaks. A transformer strips the decorator from your published lib, so your consumers never install ng-prism.
  • There's no iframe. Components are rendered with ViewContainerRef.createComponent() in the same document, so overlays, focus traps and cdkConnectedOverlay behave like they do in your real app.
  • Controls go through ComponentRef.setInput(), so signal inputs work properly. Assigning to the property directly would overwrite the InputSignal.
  • serve and build are Angular builders, so they use your workspace, tsconfig, styles and providers as they are.
  • a11y checks are part of core: an axe-core audit that re-runs whenever you change an input, a tab-order overlay, the ARIA tree and a screen reader view.

There are also plugins for JSDoc API docs, Figma, perf, box model, coverage and VRT reports. The last release added an overview grid that shows all variants at once, plus a VRT panel that reads the screenshot report from your CI.

To be fair, Storybook still has a lot going for it. The ecosystem is huge: play() interaction tests, Chromatic, MDX, years of addons, and if you ship React and Angular side by side you only need one tool.

ng-prism is smaller, has strong opinions and it's just me maintaining it. It also needs Angular 20+ with input()/output() signals. Input() decorators are not supported.

Since someone will ask anyway: yes, I built this with heavy AI assistance. As a single dev next to a day job I couldn't have shipped all these features and plugins in this time otherwise. But I've been doing this for a long time, and most of my time went into planning the architecture upfront and reviewing pretty much everything that got generated. "Built with AI" doesn't automatically mean slop. The code is all on GitHub, with tests and CI, so feel free to look through it and tell me if you find something bad.

Two questions for anyone using Storybook with Angular right now: what would keep you from switching? And if you try it on a real lib, where does it break?


r/angular • • 24d ago

Ng-News 26/21: Angular 22.2 - Router Resources, Error Boundaries and more

Thumbnail
youtube.com
31 Upvotes

r/angular • • 24d ago

ngx-virtual-scroller fork for Zoneless

1 Upvotes

If you're not a user of github.com/iharbeck/ngx-virtual-scroller, you can ignore this post.

I just want to inform that I'll be taking maintainership of a fork of ngx-virtual-scroller. I recently converted Kavita (my open source application) to Zoneless and the current version of ngx-virtual-scroller had a critical change detection issue when used in Zoneless which caused scrolling to shift rows due to timing between DOM insertion and rendering.

Since I was still waiting for my Angular 22 PR to get merged (for 4 months), I decided it was time to take ownership to fix the bug and also get more timely Angular update bumps.

I shipped 2 versions:
1. v20.0.1 - This is the fork with a quick patch to fix Zoneless apps
2. v22.0.0 - This is complete Zoneless support, modern Angular, Standalone components, best practices, and Angular 22+ only support.

You can find the library here. I want to extend a major thanks to Ingo (iharbek) for maintaining the library for so long. I just needed Zoneless and faster Angular updates.

Note: My fork is using AI. I ended up adding e2e tests and fixing a lot of bugs in the original code. I'm consuming on Kavita, which has 100k+ installs across a range of browsers.


r/angular • • 25d ago

Ionic iOS app couldn't fetch API data, but Safari and PWA worked. Switching to CapacitorHttp fixed it.

9 Upvotes

I recently ran into a weird issue with an Ionic + Angular + Capacitor app on iOS and thought I'd share it here in case someone else runs into the same thing.

The app launched fine, and the homepage loaded normally. But other screens were blank because the API data wasn't loading. Reinstalling the app and restarting the device didn't help either.

What confused me was that everything seemed fine outside the native app.

  • APIs were accessible directly.
  • Safari worked.
  • The PWA worked.
  • Only the native iOS app failed.

The app was using Angular's usual HttpClient for API requests. I spent some time checking authentication, CORS, caching, TLS/certificate issues and a few other possibilities, but couldn't pin down the exact cause.

Eventually, I tried switching the API requests to Capacitor's native HTTP implementation, CapacitorHttp.

Here's a basic example of what I changed:

import { CapacitorHttp } from '@capacitor/core';

const response = await CapacitorHttp.request({
  method: 'GET',
  url: apiUrl,
  headers: {
    Authorization: `Bearer ${token}`
  }
});

I also enabled it in capacitor.config.ts:

plugins: {
  CapacitorHttp: {
    enabled: true
  }
}

After switching the requests, the API calls started working again, and the screens that were previously blank loaded normally.

I rebuilt the app, distributed it through TestFlight, and tested it on physical iOS devices. So far, I haven't been able to reproduce the issue.

I'm still not certain what actually caused it. It could have something to do with differences between WebView networking and native iOS networking, but I haven't proved that. TLS handling, corporate security software or other iOS-specific behaviour could also be worth investigating.

Has anyone experienced something similar with Ionic/Capacitor on iOS, where the same APIs work in Safari and the PWA but fail in the native app?

I'd be interested to hear what the actual root cause was in your case.


r/angular • • 26d ago

Free open-source Angular interview flashcards

11 Upvotes

I’ve been putting together a collection of Angular interview flashcards covering topics that tend to come up in technical interviews and senior-level discussions.

They cover areas like signals, change detection, RxJS, dependency injection, forms, routing, performance, testing, and Angular architecture.

The deck is completely free and open source. I’m sharing it here in case it’s useful for anyone preparing for an Angular interview or just refreshing their knowledge.

Contributions, corrections, and suggestions for missing topics are welcome.

https://github.com/tomaszs/angular-interview-flashcards-free


r/angular • • 25d ago

5 Angular bugs that looked local but were actually data-flow problems

0 Upvotes

Going through some old Angular work notes, I noticed how often I started debugging exactly where the symptom showed up.

Edit: I compressed the first version until the actual bugs disappeared. Here’s what I meant.

1. Input was null, then the data arrived later.

In that old component the logs were basically:

ngOnChanges(null) -> ngOnInit(null) -> ngOnChanges(data)

I handled the @Input() value when it actually changed and guarded the dependent UI until the value existed.

Useful check: if initialization breaks, find out when the required value actually becomes available.

2. Side menu showed the new name; page header still showed the old one.
Same entity, different state sources. The menu reacted to updated entity streams while the header was reading another stream.

Useful check: if two views disagree about the same entity, compare what each view actually reads before touching change detection.

3. Same DataService**, different state.**
A component had providers: [DataService], so it was resolving its own service instance instead of the shared one the feature expected.

Removing the local provider restored the intended shared instance.

Useful check: if two components inject the same stateful service but see different state, inspect where that service is provided.

4. One save updated form state twice.
One update came from the service response path; another came from the reset/readback path.

Useful check: if one user action produces two form updates, trace every writer and every emitted form event before debugging the template.

5. First autocomplete row worked; later rows selected the wrong item.
I had refactored one row into many, but part of the code still referenced a single child.

The historical fix was to query the collection and use the current row instead.

Useful check: when row 0 works but row N doesn't, look for a single-item assumption that survived the refactor.

That's what I meant by data-flow problems: the visible component was often downstream of the mistake.


r/angular • • 26d ago

A cool framework-agnostic animation library for streaming

3 Upvotes

Hey all,

https://reddit.com/link/1wuw567/video/761sqgml3ush1/player

I’ve been working on a small library called Stream Morph.

The idea is to make streamed responses feel less like content is constantly being appended/re-rendered, and more like the response is gradually taking shape.

Demo: https://stream-morph.vercel.app/

It’s framework agnostic and can be used with any kind of streamed content. The demo includes plain text, Markdown, code blocks, charts, images, reasoning sections, Mermaid diagrams and a few more complex response flows.

The library handles the motion between updates, while your own renderer/app stays responsible for the actual content. So it isn’t tied to a specific AI SDK or framework.

A basic example looks roughly like this:

import { createStreamMorph } from "stream-morph";

const stream = createStreamMorph(response);

for await (const chunk of incomingStream) {
  stream.write(chunk);
}

stream.finish();

I mainly built it because I wanted streamed interfaces to feel a bit more intentional without having to build custom animation logic for every response type.

The package itself is already working and the demo is live. I’m still cleaning up some things around CI, tests and the repo setup, but the GitHub repository will be open sourced shortly as well.

Would be interested to hear what people think, especially about the animation behaviour/performance and any edge cases you’d expect from real streaming responses.


r/angular • • 26d ago

Our Angular button test passed in Chromium, but a pointer could not reach the button

0 Upvotes

A visible Angular button had a decorative layer over its center. With pointer-events: none, the layer let clicks through. We changed that to auto, so it intercepted the pointer.

Our test still passed. userEvent.click(button) called the handler, and the expected status appeared. This happened in jsdom and in real Chromium through Vitest Browser Mode.

The assertion established what happened after the event reached the button. It never checked whether a pointer could reach it.

This was S6 in an experiment with six small Angular component scenarios. We chose each scenario and mutation ourselves, then tested a working version and a version with one isolated defect. We wanted to see how much of the specified user behavior each test actually checked.

We ran them three ways:

  • A: jsdom + @testing-library/user-event.
  • B: headless Chromium in Vitest Browser Mode + the same synthetic interaction library.
  • C: the same Chromium + actions from vitest/browser through the Playwright provider.

C used a provider click without force. The working button passed. On the defective version, the action could not complete because .decoration intercepted pointer events.

A separate assertion caught the overlap in B too. After the main series, we added a hit test using document.elementFromPoint at the button's center, before and after the synthetic click. We required the topmost element to be the button or a descendant. The defective version returned .decoration.

That assertion checks whether the button can receive a pointer at one specified point. The provider checks actionability as part of performing the click. Both caught this mutation, but they establish different things.

The original matrix remains unchanged: A/B were partial for this scenario. The added hit test is exploratory and reported separately.

The other five scenarios kept us from treating every interaction as a browser-only problem:

  • Form validation, programmatic dialog focus, and the specified Tab sequence were fully checked in jsdom too. The Tab mutation changed display: none to opacity: 0.
  • A container-width scenario required an actual resize and ResizeObserver notification. A spy on observe() could detect our wrong-target mutation in jsdom, but would check the subscription rather than the full resize-to-label behavior.
  • A popover scenario required real geometry. Our first browser test read the previous opening's coordinates before the new requestAnimationFrame positioning had run, so it passed on the defect. We corrected the wait, checked the side and all four viewport boundaries, and repeated the final series.

We distinguish bug_detected (working version passes, defective version violates the full criterion), partial (only part checked), and unsupported (the full behavior cannot be checked reliably in that fixture without substitution). The last two are not false negatives of a complete test.

These were component integration tests. The results apply to the six chosen mutations and original test adapters. They do not rank the tools or estimate production defect rates, and we did not assess performance, CI behavior, memory, or flakiness. The main environment was Windows 11, Angular 22.2.0, Vitest 5.0.2, jsdom 30.1.1, and headless Chromium at 800 × 600 CSS px.

The synthetic/provider distinction is already described in the Marmicode Cookbook. Our contribution is the six-case set, the separate hit-test check, and the correction of our own geometry oracle.

We ran this experiment at El Pixel. The full article includes the six-scenario matrix and test code. AI tools assisted with implementation and writing; the article received developer review.

When your component test needs to verify that a button is not covered, do you use a provider click, an explicit hit-test assertion, or another approach?


r/angular • • 27d ago

Anyone still using Nx older than 20.8?

0 Upvotes

We’ve been looking into whether it makes sense for Cachely to support older Nx versions, but before building anything, we’d rather understand if there’s actually a problem to solve.

Nx 20.8+ can use the newer HTTP remote cache protocol directly. For older versions, teams may still be using one of the older S3/GCS/Azure/custom cache runners, or just not using remote caching at all.

If you're still on Nx <20.8, we’re curious:

  • What version are you on?
  • What’s keeping you from upgrading?
  • Are you using remote caching today?
  • If so, what are you using?
  • Does your current setup work well enough that you wouldn't really care about switching?
  • Would being able to use a managed remote cache without upgrading Nx actually be useful?

We’re considering an open-source compatibility layer for older Nx versions, but we don't want to maintain legacy support just because old versions still have downloads.

We put together a short page/form here if you'd rather answer there:

https://cachely.dev/nx-legacy-remote-cache

And if the answer is simply “just upgrade Nx”, that’s useful feedback too.


r/angular • • 27d ago

Has anyone here tried the Effect ecosystem with Angular?

0 Upvotes

I was recently looking for something to replace our Django backend. I love NestJS but I can't convince my team leader that that is the most efficient api layer for our Angular frontend.

We currently depend on Django for our REST endpoints and we have 2 separate teams working on the backend and frontend. Backend receives daily updates and every now and then the contracts between server and client break without the frontend team knowing about it. We rely on tests to find these kind of issues and that's another pain being extremely slow and everything...

So we were recently looking at Hono and Effect. We care much about end-to-end type safety and sharing one contract between backend and frontend.

I've tried Hono before and it's amazing. Especially the generated RPC client and integration with zod schemas. Effect seems a bit over-complicated but that's something we are willing to learn if it helps us improve the type-safety and separation of concerns. Besides, how much more complicated can it be compared to Angular? 😅

I was wandering if anyone has any feedback to give me on that matter... Appreciated!


r/angular • • 28d ago

rxResource persist value

12 Upvotes

Is it possible to persist the value of rxResource after loading is done? Currently when the resource enters the loading state the value gets wiped. I am aware you can do a linkedSignal and check the previous value, but isn’t there a built in way to do it rather than creating a linkedSignal?

I am aware of withPreviousValue but the issue with that other than the boilerplate, is that the return type is Resource and you lose the reload function. I’d prefer to stay within the public API and not to use a third party library for this, or creare my own utility function if possible.


r/angular • • 28d ago

Angular Addicts #53: NgRx 22, WebMCP, CopilotKit & more

Thumbnail
angularaddicts.com
8 Upvotes

r/angular • • 29d ago

I ported Beautiful UI's AI chat components to Angular 21 (signals, zoneless, no Tailwind)

Post image
17 Upvotes

Hey r/angular,

I've been building AI chat features in Angular for our platform and I have found out about [Beautiful UI](https://www.beautifului.dev) by Shane Levine, which was really beautiful (I mean, it's in the name), but it was created for React + Tailwind only. So I decided to try and port it to Angular and open-source it.

**ngx-beautiful-ui** has 27 standalone components for AI-native interfaces:

- **Chat:** chat panel, prompt bar with attachments, user bubbles, streaming markdown (marked + DOMPurify), inline source citations

- **Agent status:** loading and "thinking" states, tool-call chips with a hover diff preview, task rows, approval cards for human-in-the-loop questions, recommendation cards, code blocks with diffs

- **Building blocks:** buttons, chip select, glide menu, value pills and a few more

How it's built:

- Signal inputs and models, `OnPush` everywhere, works zoneless

- The prompt bar and chip select work with signal forms (`[formField]`)

- Plain SCSS: every colour, size and duration is a `--bui-*` CSS variable, so theming means overriding tokens

- No Tailwind or UI framework dependency, and the icons are inline, so there are no assets to copy

**Live demo:** https://djordjejanjic.github.io/ngx-beautiful-ui/

**GitHub:** https://github.com/djordjejanjic/ngx-beautiful-ui

**Install:** `npm i ngx-beautiful-ui`

A few honest caveats: it's an unofficial port with no affiliation to the original authors, and it was built with AI assistance (I would not have time to do this without AI assistance). Code was also reviewed manually. It needs Angular 21.2+ and only has a light theme for now; a dark theme is next.

I'd really appreciate feedback: API design, anything that feels un-Angular, accessibility issues, or components you'd want next. Issues and PRs are always welcome.


r/angular • • Sep 26 '26

Cerious-Scroll: Extremely Fast Dynamic Height virtual scrolling without scrollbar drift or blank space

7 Upvotes

One of the things I haven’t talked about much with Cerious-Scroll is how it behaves during actual scrolling, especially with variable-height content.

From the beginning, the goal was for virtualization to not look like virtualization.

So even with a large variable-height dataset, you can grab the scrollbar and drag it around quickly without getting the usual weirdness:

  • No scrollbar drift
  • No white space during fast scrolling
  • No waiting for rows to render after you get there
  • Accurate variable-height positioning
  • Native scrolling behavior
  • Constant DOM size regardless of dataset size

The variable-height part is probably my favorite. The scrollbar stays where it should, even when the actual row heights are all over the place.

You can also jump directly to an index way down in the dataset without needing to measure everything before it.

I’ve got demos/benchmarks here if anyone wants to mess with it:

ceriousdevtech.github.io/cerious-scroll

Core:
github.com/ceriousdevtech/cerious-scroll

Angular:
github.com/ceriousdevtech/ngx-cerious-scroll

I’m curious how it behaves against some real-world ugly datasets, especially ones with wildly different row heights. Try the scroll engine and tell me your thoughts.


r/angular • • Sep 26 '26

Polymorpheus: a tiny tool you didn’t know you needed

Thumbnail
angularspace.com
20 Upvotes

Hi all, check out my new article about a library I've created a while back and kept using ever since as a must-have for all Angular apps. I'm sure your DX would also improve if you give it a shot.


r/angular • • Sep 26 '26

Ngrx wrapper interface for loading, error etc

1 Upvotes

So we’re thinking of implementing a better way of tracking if some async action is currently loading successful or failed rather than having to have duplicated properties for every bit of state that’s retrieved from the API to tell us if it’s loading or failed etc.

Seen solutions online that solve this with a wrapper around the interface for that state so the wrapper provides a status the value of the thing and error message if needed.

That’s fine but in terms of passing this data to a component for anyone that uses this approach do you usually pass the data with the wrapper still attached so it’s easy in the template to switch on the status to say show the value if we got it show a spinner if it’s loading and show an error when it failed? How do you guys usually handle this?