{"id":26851256,"url":"https://github.com/ngbox/ng-observe","last_synced_at":"2025-05-05T16:21:44.499Z","repository":{"id":40381215,"uuid":"345563321","full_name":"ngbox/ng-observe","owner":"ngbox","description":"Angular reactivity streamlined...","archived":false,"fork":false,"pushed_at":"2022-08-18T08:36:29.000Z","size":387,"stargazers_count":70,"open_issues_count":1,"forks_count":1,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-05-01T08:23:22.463Z","etag":null,"topics":["angular","angular2","observable","observer","reactive-programming","rxjs","streams","subscription","utility"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ngbox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-03-08T07:12:17.000Z","updated_at":"2025-04-12T12:46:48.000Z","dependencies_parsed_at":"2022-08-09T18:51:23.825Z","dependency_job_id":null,"html_url":"https://github.com/ngbox/ng-observe","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngbox%2Fng-observe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngbox%2Fng-observe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngbox%2Fng-observe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngbox%2Fng-observe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ngbox","download_url":"https://codeload.github.com/ngbox/ng-observe/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252531882,"owners_count":21763293,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","angular2","observable","observer","reactive-programming","rxjs","streams","subscription","utility"],"created_at":"2025-03-30T22:19:16.140Z","updated_at":"2025-05-05T16:21:44.482Z","avatar_url":"https://github.com/ngbox.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cbr /\u003e\u0026nbsp;\u003cbr /\u003e\n  \u003cimg alt=\"ng-observe logo\" src=\"https://user-images.githubusercontent.com/34455572/115234990-54499300-a122-11eb-84ae-30640268fded.png\" width=\"192\" align=\"middle\" /\u003e\n\u003c/p\u003e\n\u003ch1 align=\"center\"\u003e\n  ng-observe\n  \u003cbr /\u003e\u0026nbsp;\u003cbr /\u003e\n\u003c/h1\u003e\n\nAngular reactivity streamlined...\n\n### Why?\n\n- Unlike [AsyncPipe](https://angular.io/api/common/AsyncPipe), you can use it in component classes and even in directives.\n- Feels more reactive than unsubscribing on destroy (be it handled by a decorator, triggered by a subject, or done by a direct call in the lifecycle hook).\n- Reduces the complexity of working with streams.\n- Works in zoneless apps. (v1.1.0+)\n\n### How it works\n\n- Extracts emitted value from observables.\n- Marks the component for change detection.\n- Leaves no subscription behind.\n- Clears old subscriptions and creates new ones at each execution if used in getters, setters or methods.\n\n### How to use\n\nInstall the package, and you are good to go. No module import is necessary.\n\n```\nnpm install ng-observe\n```\n\n...or...\n\n```\nyarn add ng-observe\n```\n\n### Example\n\nWe can subscribe to a stream with the `AsyncPipe` in component templates, but we can't use it in component or directive classes.\n\n```typescript\n@Component({\n  template: '{{ fooBar$ | async }}',\n})\nclass DemoComponent {\n  foo$ = of('foo');\n\n  get fooBar$() {\n    return foo$.pipe(map(val =\u003e val + 'bar'));\n  }\n}\n```\n\nWith ng-observe, we don't need to pipe the stream.\n\n```typescript\nimport { OBSERVE, OBSERVE_PROVIDER, ObserveFn } from 'ng-observe';\n\n@Component({\n  template: '{{ fooBar }}',\n  providers: [OBSERVE_PROVIDER],\n})\nclass DemoComponent {\n  foo = this.observe(of('foo'));\n\n  get fooBar() {\n    return this.foo.value + 'bar';\n  }\n\n  constructor(@Inject(OBSERVE) private observe: ObserveFn) {}\n}\n```\n\nYou can see other examples at links below:\n\n- [Basic example](https://stackblitz.com/edit/ng-observe?file=src%2Fapp%2Fapp.ts)\n- [Using with Angular router](https://stackblitz.com/edit/ng-observe-router?file=src%2Fapp%2Fapp.ts)\n- [Using with NgRx](https://stackblitz.com/edit/ng-observe-ngrx?file=src%2Fapp%2Fapp.ts)\n- [Zoneless](https://stackblitz.com/edit/ng-observe-zoneless?file=src%2Fapp%2Fapp.ts)\n\n\u003e **Important Note:** Do not destructure a collection created by the `ObserveFn`. Otherwise, the reactivity will be lost. Use `toValue` or `toValues` to convert elements of the collection to instances of `Observed` instead.\n\nYou can read [this Medium article](https://ozak.medium.com/angular-reactivity-streamlined-831754b60a11) to learn about what the motivation behind ng-observe is.\n\n### API\n\n#### OBSERVE_PROVIDER\n\nTo use ng-observe in your components and directives, add `OBSERVE_PROVIDER` to providers array in metadata.\n\n#### ObserveFn\n\nThis function is used to extract a single stream's value. You can inject it via the `OBSERVE` injection token.\n\n```typescript\nimport { OBSERVE, OBSERVE_PROVIDER, ObserveFn } from 'ng-observe';\n\n@Component({\n  template: '{{ foo.value }}',\n  providers: [OBSERVE_PROVIDER],\n})\nclass Component {\n  foo = this.observe(of('foo'));\n\n  constructor(@Inject(OBSERVE) private observe: ObserveFn) {}\n}\n```\n\nYou can extract multiple streams' value too.\n\n```typescript\nimport { OBSERVE, OBSERVE_PROVIDER, ObserveFn } from 'ng-observe';\n\n@Component({\n  template: '{{ state.foo }} {{ state.bar }}',\n  providers: [OBSERVE_PROVIDER],\n})\nclass Component {\n  state = this.observe({ foo: of('foo'), bar: of('bar') });\n\n  constructor(@Inject(OBSERVE) private observe: ObserveFn) {}\n}\n```\n\nIt works with arrays as well.\n\n```typescript\nimport { OBSERVE, OBSERVE_PROVIDER, ObserveFn } from 'ng-observe';\n\n@Component({\n  template: '{{ state[0] }} {{ state[1] }}',\n  providers: [OBSERVE_PROVIDER],\n})\nclass Component {\n  state = this.observe([of('foo'), of('bar')]);\n\n  constructor(@Inject(OBSERVE) private observe: ObserveFn) {}\n}\n```\n\n#### ObserveService\n\nYou can call `ObserveService`'s `value` and `collection` methods explicitly instead of `ObserveFn`. This offers a very slight (ignorable in most cases) performance improvement.\n\n```typescript\nimport { ObserveService } from 'ng-observe';\n\n@Component({\n  template: '{{ foo.value }} {{ state[0] }} {{ state[1] }}',\n  providers: [ObserveService],\n})\nclass Component {\n  foo = this.observe.value(of('foo'));\n\n  state = this.observe.collection([of('foo'), of('bar')]);\n\n  constructor(private observe: ObserveService) {}\n}\n```\n\n#### Observed\n\n`ObserveFn` infers types for you, but if you want to assign an observed value later, you can use `Observed` class for type annotation.\n\n```typescript\nimport { OBSERVE, OBSERVE_PROVIDER, Observed } from 'ng-observe';\n\n@Component({\n  template: '{{ foo.value }}',\n  providers: [OBSERVE_PROVIDER],\n})\nclass Component {\n  foo: Observed\u003cstring\u003e;\n\n  constructor(@Inject(OBSERVE) private observe: ObserveFn) {\n    this.foo = this.observe(of('foo'));\n  }\n}\n```\n\n#### toValue\n\n`toValue` converts an element in the collection to a reactive observed value. Returns an instance of the `Observed` class.\n\n```typescript\nimport { OBSERVE, OBSERVE_PROVIDER, Observed, ObserveFn, toValue } from 'ng-observe';\n\n@Component({\n  template: '{{ foo.value }} {{ bar.value }}',\n  providers: [OBSERVE_PROVIDER],\n})\nclass Component {\n  foo: Observed\u003cstring\u003e;\n\n  bar: Observed\u003cstring\u003e;\n\n  constructor(@Inject(OBSERVE) private observe: ObserveFn) {\n    const state = this.observe({ foo: of('foo'), bar: of('bar') });\n    this.foo = toValue(state, 'foo');\n    this.bar = toValue(state, 'bar');\n  }\n}\n```\n\n#### toMappedValue\n\nYou can use `toMappedValue` to get a reactive observed value mapped from the collection. Returns an instance of the `Observed` class.\n\n```typescript\nimport { OBSERVE, OBSERVE_PROVIDER, Observed, ObserveFn, toMappedValue } from 'ng-observe';\n\n@Component({\n  template: '{{ fooBar.value }}',\n  providers: [OBSERVE_PROVIDER],\n})\nclass Component {\n  fooBar: Observed\u003cstring\u003e;\n\n  constructor(@Inject(OBSERVE) private observe: ObserveFn) {\n    const state = this.observe({ foo: of('foo'), bar: of('bar') });\n    this.fooBar = toMappedValue(state, ({ foo, bar }) =\u003e `${foo} ${bar}`);\n  }\n}\n```\n\n#### toValues\n\n`toValues` converts all elements in collection to reactive observed values. Returns an array/object the indices/keys of which will be the same with the input collection. Each element will be an instance of the `Observed` class.\n\n```typescript\nimport { OBSERVE, OBSERVE_PROVIDER, Observed, ObserveFn, toValues } from 'ng-observe';\n\n@Component({\n  template: '{{ foo.value }} {{ bar.value }}',\n  providers: [OBSERVE_PROVIDER],\n})\nclass Component {\n  foo: Observed\u003cstring\u003e;\n\n  bar: Observed\u003cstring\u003e;\n\n  constructor(@Inject(OBSERVE) private observe: ObserveFn) {\n    const state = this.observe({ foo: of('foo'), bar: of('bar') });\n    const { foo, bar } = toValues(state);\n    this.foo = foo;\n    this.bar = bar;\n  }\n}\n```\n\n#### isCollection\n\nCollections observed by ng-observe are plain arrays or objects, but you can detect them with `isCollection` function. It returns `true` when input is an observed collection, and `false` when not.\n\n```typescript\nimport { isCollection, OBSERVE, OBSERVE_PROVIDER, ObserveFn } from 'ng-observe';\n\n@Component({\n  template: '\u003c!-- not important for this example --\u003e',\n  providers: [OBSERVE_PROVIDER],\n})\nclass Component {\n  constructor(@Inject(OBSERVE) private observe: ObserveFn) {\n    const state = this.observe({ foo: of('foo'), bar: of('bar') });\n    console.log(isCollection(state)); // true\n  }\n}\n```\n\n### Sponsors\n\n[![volosoft](https://user-images.githubusercontent.com/34455572/115241777-dc7f6680-a129-11eb-8318-4f3c811547e8.png)](https://volosoft.com/)\n\n\u003chr /\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"255\" src=\"https://user-images.githubusercontent.com/34455572/115242872-f8373c80-a12a-11eb-9b52-f3b75bd2f61e.png\" alt=\"Developed by NG Box\" /\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fngbox%2Fng-observe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fngbox%2Fng-observe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fngbox%2Fng-observe/lists"}