npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ngx-signal-utils

v18.0.0

Published

Angular Signal watch utils

Downloads

80

Readme

ngx-signal-utils

Helper functions for working with Angular Signals in a cleaner way.

Provides several helper functions:

  • An Angular equivalent of Vue's watch() function. Some might consider watch() cleaner and less bug-prone than Angular's effect(), and thus produces more maintainable code.

  • watchChanges() is similar to watch() but rather than passing the current value of a tracked signal, it passes a generically-typed version of SimpleChange.

  • watchDebug() writes Signal value changes to the console.

watch()

watch() implementation is similar to Vue's at https://vuejs.org/api/reactivity-core.html#watch, with the options paremeter differing.

// watching single source
function watch<T>(
  source: WatchSource<T>,
  callback: WatchCallback<T>,
  options?: WatchOptions
): WatchStopHandle

// watching multiple sources
function watch<T>(
  sources: WatchSource<T>[],
  callback: WatchCallback<T[]>,
  options?: WatchOptions
): WatchStopHandle

type WatchCallback<T> = (
  value: T,
  oldValue: T,
  onCleanup: (cleanupFn: () => void) => void
) => void

type WatchSource<T = any> = Signal<T> | InputSignal<T> | WritableSignal<T>;

type WatchOptions = {
  immediate?: boolean
  once?: boolean
  wrapCallback?: boolean
} & CreateEffectOptions;

WatchOptions:

| Option | Type | Default Value | Description | | ----- | ---- | ------------- | ----------- | | immediate | boolean | true | Run the callback immediately when watcher created | | once | boolean | false | Run the callback only once. Watcher is destroyed after it runs. | | wrapCallback | boolean | false | Wraps the callback in a setTimeout() with 0ms delay | | injector | boolean | undefined | undefined | See https://angular.io/api/core/CreateEffectOptions | | manualCleanup | boolean | undefined | undefined | See https://angular.io/api/core/CreateEffectOptions | | allowSignalWrites | boolean | undefined | undefined | See https://angular.io/api/core/CreateEffectOptions |

Why use watch() over effect()?

  • Common bugs are negated, whereby effect() callbacks don't trigger because signal getter invocations are inside skipped code blocks. The watch() callback should always run when you expect it to.

  • Watched values are declared explicitly in the watch source(s), and their unwrapped values are passed as a value / value array to the callback. This means it usually isn't necessary to invoke signal getters in the watch callback. It also negates the need, as some do with effect(), to run signal getters in the first lines of the effect() callback as a kind of 'declaration', which looks strange and not in keeping with common JS / TS practices. This arguably leads to cleaner, more maintainable code.

watchChanges()

// watching single source
function watchChanges<T>(
  source: WatchSource<T>,
  callback: WatchChangesCallback<SimpleChangeGeneric<T>>,
  options?: WatchOptions
): WatchStopHandle

// watching multiple sources
function watchChanges<T>(
  sources: WatchSource<T>[],
  callback: WatchChangesCallback<MapSourcesSimpleChanges<T, false>>, // callback param is array of typed SimpleChange objects, where value / previousValue are unwrapped signal values
  options?: WatchOptions
): WatchStopHandle

type WatchCallback<T> = (
  value: T,
  oldValue: T,
  onCleanup: (cleanupFn: () => void) => void
) => void

Similar to watch() but rather than passing the current value of a tracked signal to the watcher callback, it passes a generically-typed version of SimpleChange. Just like the SimpleChanges parameter to ngOnChanges(), it provides the current and previous unwrapped value of the tracked signal.

Why use watchChanges()?

One can, in many or even most cases, replace monolithic ngOnChanges() with more streamlined and cleaner reactive code. This means you don't have to handle all of your input change side-effects from that single lifecycle hook.

watchDebug()

Accepts a sources object of key, signal values. Writes any value changes to the console. Useful for debugging.

Additional Info

Should you invoke a signal getter (i.e. this.mySignal()) inside a watcher callback, it will not cause the signal to be watched / callback to trigger. This is because the watcher code wraps the callback in untracked().