ngx-hooks v0.0.5
:warning: WARNING: It only works with Angular version >=8.x.x with Ivy render enabled (doesn't work with aot build of old compiler).
Table of Contents
- Why Function APIs?
- Installation
- Usage
- Lifecycle
- ref
- computed
- observe
- watch
- inject
- createProvider
- Helpers
- License
- FAQs
Why Function APIs?
- More declarative way to write Angular Components, Directives and Services
- Reuse same functions between different components/directives so no need to create services to splitting out methods to reduce component file or making it reusable.
- Easy to split up functionality into functions of large component without creating unnecessarily more components.
- Encourages to write implementation detail free tests
Installation
This library is distributed via npm registry:
npm install --save ngx-hooksThis library has @angular/core and rxjs as peerDependencies.
Typescript Configuration
This package contains uncompiled typescript (.ts) files, you need to configure it manually.
To enable typescript compilation of this package along with your angular project, you need to configure source files in tsconfig.json like:
{
// ...
include: ['./node_modules/ngx-hooks/**/*.ts'],
// ...
}Usage
Component
Simple usage of function component
import { Component } from '@angular/core';
import { FunctionComponent, NgHooksContext, ref } from 'ngx-hooks';
@Component({
selector: 'app-component',
template: '<h1>{{title}}</h1>',
})
@FunctionComponent() // <- to make Function Component
class AppComponent {
title: string;
// required by @FunctionComponent() and must be static
static ngHooks(context: NgHooksContext<AppComponent>) {
const title = ref('Angular Function APIs');
return { title };
}
}Directive
Simple usage of a function directive which highlights a text with yellow color
import { Directive, ElementRef } from '@angular/core';
import { FunctionDirective, NgHooksContext, inject } from 'ngx-hooks';
@Directive({
selector: '[highlight]',
})
@FunctionDirective() // <- to make Function Directive
class HighlightDirective {
// required by @FunctionDirective() and must be static
static ngHooks(context: NgHooksContext<HighlightDirective>) {
const elementRef = inject(ElementRef);
elementRef.nativeElement.style.backgroundColor = 'yellow';
}
}Lifecycle
Lifecycle can be used in Function component/directives and Provider or any composed function. It must be used in ngHooks function body or custom compose function body, can't be used in nested callback
import { onDestroy, ref } from 'ngx-hooks';
class AppComponent {
static ngHooks(context: NgHooksContext<AppComponent>) {
const count = ref(0);
const interval = setInterval(() => {
ref.value++;
}, 1000);
onDestroy(() => {
clearInterval(interval);
});
return { count };
}
}Provided lifecycle:
onInitonDestroyonChangesonDoCheckonAfterContentInitonAfterContentCheckedonAfterViewInitonAfterViewChecked
Note: Custom lifecycle can be created via composeLifecycle here
ref
ref() is to creating a reactive state
import { ref } from 'ngx-hooks';
class AppComponent {
static ngHooks(context: NgHooksContext<AppComponent>) {
const title = ref('Angular');
setTimeout(() => {
title.value = 'Angular Function API';
}, 3000);
return { title };
}
}computed
computed takes a getter function in first argument and returns a computed reactive value based on a getter function.
import { computed, ref } from 'ngx-hooks';
class AppComponent {
static ngHooks(context: NgHooksContext<AppComponent>) {
const count = ref(0);
const double = computed(() => count.value * 2);
setInterval(() => {
count.value++;
}, 1000);
return { double };
}
}it does also take second argument as setter which will be invoked when computed reactive value is set.
import { computed, ref } from 'ngx-hooks';
class AppComponent {
static ngHooks(context: NgHooksContext<AppComponent>) {
const count = ref(0);
const double = computed(() => count.value * 2, (double) => (count.value = double / 2));
double.value = 1000;
return { double };
}
}Note: assigning to a computed value will not have any effect if setter is not provided
observe
observe returns a reactive value by observing a property of any object.
import { observe, computed } from 'ngx-hooks';
class AppComponent {
static ngHooks(context: NgHooksContext<AppComponent>) {
const id = observe(context, (context) => context.id);
const currentUser = computed(() => USERS.find((user) => user.id === id.value));
return { currentUser };
}
}watch
It runs a watcher function when ever dependency or dependencies change. Dependency can be a reactive value or a getter function.
import { watch, observe, ref } from 'ngx-hooks';
class AppComponent {
static ngHooks(context: NgHooksContext<AppComponent>) {
const id = observe(context, (context) => context.id);
const user = ref(null);
watch(id, async (newId, oldId, onCleanup) => {
const result = await fetch('some.domain.url/api/user/' + newId);
const data = await result.json();
user.value = data;
onCleanup(() => {
// cleanup functionality
});
});
return { user };
}
}Watching multiple sources
import { watch, observe } from 'ngx-hooks';
class AppComponent {
static ngHooks(context: NgHooksContext<AppComponent>) {
const id = observe(context, (context) => context.id);
const params = observe(context, (context) => context.params);
watch([id, () => params.value.user_role], ([newId, newUserRole], [oldId, oldUserRole], onCleanup) => {
// ...
onCleanup(() => {
// cleanup functionality
});
});
// ...
}
}Options
watch takes options object (optional) in last function parameter.
watch(
id,
() => {
// call immediately when id changes and will not call immediately
},
{ mode: 'sync', lazy: true }
);Watch mode:
By default, it flushes after content checked. this behaviour can be changed via
modeoption.sync: flushes synchronouslycontent: flushes after content checked (default)view: flushes after view checked
Lazy Watch:
When lazy is
true, watcher function will not run immediately. (default isfalse)
Note: watch fallbacks to sync mode if it is used in createProvider.
inject
inject is same as Angular's Injector.get.
import { inject } from 'ngx-hooks';
class AppComponent {
static ngHooks(context: NgHooksContext<AppComponent>) {
const store = inject(Store);
// do anything with store
}
}createProvider
createProvider creates provider which can be injected in components, directives or providers. the return value must be an object.
import { createProvider, inject } from 'ngx-hooks';
const [LogService, LogServiceProvider] = createProvider('LogService', () => {
function log(...args) {
console.log('Log:', ...args);
}
return { log };
});
@Component({
// ...
providers: [LogServiceProvider],
})
@FunctionComponent()
class AppComponent {
static ngHooks(context: NgHooksContext<AppComponent>) {
const logService = inject(LogService);
logService.log('log some useful stuff');
}
}Usage with object destructuring:
import { createProvider } from 'ngx-hooks'; const { token: LogService, provider: LogServiceProvider } = createProvider('LogService', () => { // ... });Usage with
providedIn:providedInisrootby defaultimport { createProvider } from 'ngx-hooks'; const { token: LogService, provider: LogServiceProvider } = createProvider('LogService', { providedIn: AppModule, factory: () => { // ... }, });
Note: In provider, only onDestroy lifecycle can be used other lifecycle will have no effects.
Helpers
composeLifecycleit can be use to compose custom lifecycle which give can be used in composed functions as well.
import { composeLifecycle } from 'ngx-hooks'; const onWriteValue = composeLifecycle<(value: string) => void>('writeValue'); @Component({ // ... }) @FunctionComponent({ lifecycle: [onWriteValue], }) class AppComponent { static ngHooks(context: NgHooksContext<AppComponent>) { onWriteValue((value) => { // do something with value }); } }fromRefit can be used to un-wrap ref or Object/Array of refs deeply
import { fromRef, ref } from 'ngx-hooks'; const id = ref('001'); fromRef(id); // '001' const refsArray = [ref(1), ref(2)]; fromRef(refsArray); // [1, 2]; const refMap = { ref1: ref('value1'), deep: { nestedRef: ref('value2'), }, }; fromRef(refMap); // {ref1: 'value1', deep: {nestedRef: 'value2'}}
FAQs
Why ngHooks method is static method?
To avoid confusion of
thiskeyword as we restricted the usage of it.As we don't allow to use
thisinngHooksfunction but if it would be a class method thenthisshould be referenced toclassinstance as per semantic of Javascript.
LICENSE
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago