How to write good libraries for Angular

The web is a feature-rich environment. We can navigate virtual reality with a gamepad, play synthesizer with a MIDI keyboard, buy goods with just one touch of our finger. All of these impressive capabilities are provided by native APIs, which, like their functionality, are extremely diverse.



Angular is an excellent platform with some of the best tools in the front-end environment. And, of course, there is a certain way to do it "in Angulyar" way. What I personally love about this framework is the satisfaction that you get when everything is done right: neat code, clear architecture. Let's take a look at what makes the code properly written in Angular.





The Angular way



Angular, , , , . , , , Angular ยซ ยป. : . opensource- Web APIs for Angular. โ€” , API Angular. @ng-web-apis/intersection-observer.



, :



  1. Angular , JavaScript- .
  2. Angular , .
  3. Angular Observable, API .


.



vs



, , IntersectionObserver:



const callback = entries => { ... };
const options = {
   root: document.querySelector('#scrollArea'),
   rootMargin: '10px',
   threshold: 1
};
const observer = new IntersectionObserver(callback, options);

observer.observe(document.querySelector('#target'));




API



, , . Angular :



<div
   waIntersectionObserver
   waIntersectionThreshold="1"
   waIntersectionRootMargin="10px"
   (waIntersectionObservee)="onIntersection($event)"
>
   I'm being observed
</div>


Angular Payment Request API. , .

2 : , โ€” . . . -, . observe/unobserve.



IntersectionObserver Map . , , :



@Directive({
   selector: '[waIntersectionObserver]',
})
export class IntersectionObserverDirective extends IntersectionObserver
   implements OnDestroy {
   private readonly callbacks = new Map<Element, IntersectionObserverCallback>();

   constructor(
       @Optional() @Inject(INTERSECTION_ROOT) root: ElementRef<Element> | null,
       @Attribute('waIntersectionRootMargin') rootMargin: string | null,
       @Attribute('waIntersectionThreshold') threshold: string | null,
   ) {
       super(
           entries => {
               this.callbacks.forEach((callback, element) => {
                   const filtered = entries.filter(({target}) => target === element);

                   return filtered.length && callback(filtered, this);
               });
           },
           {
               root: root && root.nativeElement,
               rootMargin: rootMargin || ROOT_MARGIN_DEFAULT,
               threshold: threshold
                 ? threshold.split(',').map(parseFloat)
                 : THRESHOLD_DEFAULT,
           },
       );
   }

   observe(target: Element, callback: IntersectionObserverCallback = () => {}) {
       super.observe(target);
       this.callbacks.set(target, callback);
   }

   unobserve(target: Element) {
       super.unobserve(target);
       this.callbacks.delete(target);
   }

   ngOnDestroy() {
       this.disconnect();
   }
}


โ€” .



Dependency Injection



DI Angular , . . , , . , , . :



@Directive({
   selector: '[waIntersectionRoot]',
   providers: [
       {
           provide: INTERSECTION_ROOT,
           useExisting: ElementRef,
       },
   ],
})
export class IntersectionRootDirective {}


:



<div waIntersectionRoot>
   ...
   <div
       waIntersectionObserver
       waIntersectionThreshold="1"
       waIntersectionRootMargin="10px"
       (waIntersectionObservee)="onIntersection($event)"
   >
       I'm being observed
   </div>
   ...
</div>


DI , , Web Audio API Angular.

โ€” . . , - -, .



DI IntersectionObserver RxJS Observable, .



Observables



API , Angular RxJs . Observable, , โ€” . - IntersectionObserver, Observable. , :



@Injectable()
export class IntersectionObserveeService extends Observable<IntersectionObserverEntry[]> {
   constructor(
       @Inject(ElementRef) {nativeElement}: ElementRef<Element>,
       @Inject(IntersectionObserverDirective)
       observer: IntersectionObserverDirective,
   ) {
       super(subscriber => {
           observer.observe(nativeElement, entries => {
               subscriber.next(entries);
           });

           return () => {
               observer.unobserve(nativeElement);
           };
       });
   }
}




Observable, IntersectionObserver. Angular, new-.



Observable- Geolocation API Resize Observer API, .

Output. EventEmitter, Observable , , :



@Directive({
   selector: '[waIntersectionObservee]',
   outputs: ['waIntersectionObservee'],
   providers: [IntersectionObserveeService],
})
export class IntersectionObserveeDirective {
   constructor(
       @Inject(IntersectionObserveeService)
       readonly waIntersectionObservee: Observable<IntersectionObserverEntry[]>,
   ) {}
}


, RxJs-, map, filter, switchMap, .





, IntersectionObserver Observable. DI . 1 .gzip Github npm.



, , . , . , , Internet Explorer.



, . , API Angular. - , Canvas MIDI-, โ€” .



GDG DevParty Russia, API Angular. , :






All Articles