Browse Source

Merge pull request #17054 from abpframework/connection-status-with-signal

connection status service signal implementation
pull/17358/head
Mahmut Gundogdu 3 years ago
committed by GitHub
parent
commit
6da7fb1848
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      docs/en/UI/Angular/Internet-Connection-Service.md
  2. 34
      npm/ng-packs/packages/core/src/lib/services/internet-connection-service.ts
  3. 100
      npm/ng-packs/packages/core/src/lib/tests/internet-connection.service.spec.ts
  4. 17
      npm/ng-packs/packages/theme-shared/src/lib/components/internet-connection-status/internet-connection-status.component.ts

30
docs/en/UI/Angular/Internet-Connection-Service.md

@ -0,0 +1,30 @@
# Internet Connection Service
`InternetConnectionService` is a service which is exposed by the `@abp/ng.core` package. **You can use this service in order to check your internet connection**
## Getting Started
When you inject the InternetConnectionService you can get the current internet status, and it gets immediately updated if the status changes.
`InternetConnectionService` provides two choices to catch the network status:
1. Signal (readonly)
2. Observable
# How To Use
İt's easy, just inject the service and get the network status.
**You can get via signal**
```ts
class SomeComponent{
internetConnectionService = inject(InternetConnectionService);
isOnline = this.internetConnectionService.networkStatus
}
```
**or you can get the observable**
```ts
class SomeComponent{
internetConnectionService = inject(InternetConnectionService);
isOnline = this.internetConnectionService.networkStatus$
}
```
To see how we implement to the template, check the `InternetConnectionStatusComponent`

34
npm/ng-packs/packages/core/src/lib/services/internet-connection-service.ts

@ -1,18 +1,32 @@
import { DOCUMENT } from '@angular/common';
import { Injectable, inject } from '@angular/core';
import { fromEvent, merge, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { Injectable, computed, inject, signal } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class InternetConnectionService{
protected readonly window = inject(DOCUMENT).defaultView;
protected readonly navigator = this.window.navigator;
readonly document = inject(DOCUMENT)
readonly window = this.document.defaultView;
readonly navigator = this.window.navigator;
networkStatus$ = merge(
of(navigator.onLine),
fromEvent(window, 'offline'),
fromEvent(window, 'online')
).pipe(map(() => navigator.onLine))
private status$ = new BehaviorSubject<boolean>(this.navigator.onLine)
private status = signal(this.navigator.onLine);
networkStatus = computed(() => this.status())
constructor(){
this.window.addEventListener('offline', () => this.setStatus(false));
this.window.addEventListener('online', () => this.setStatus(true));
}
setStatus(val:boolean){
this.status.set(val)
this.status$.next(val)
}
get networkStatus$(){
return this.status$.asObservable()
}
}

100
npm/ng-packs/packages/core/src/lib/tests/internet-connection.service.spec.ts

@ -0,0 +1,100 @@
import { TestBed} from '@angular/core/testing';
import { DOCUMENT } from '@angular/common';
import { InternetConnectionService } from '../services/internet-connection-service';
import { first } from 'rxjs';
let service: InternetConnectionService;
describe('Internet connection when disconnected', () => {
const events = {};
const addEventListener = jest.fn((event, callback) => {
events[event] = callback;
});
const mockDocument = { defaultView: {navigator: {onLine: false}, addEventListener } }
beforeAll(() => {
TestBed.configureTestingModule({
providers:[{provide:DOCUMENT, useValue: mockDocument}]
})
service = TestBed.inject(InternetConnectionService);
});
it('document should be created', () => {
expect(service.document).toEqual(mockDocument);
});
it('signal value should be false', () => {
expect(service.networkStatus()).toEqual(false);
});
it('observable value should be false',
(done: any) => {
service.networkStatus$.pipe(first()).subscribe(value => {
expect(value).toBe(false)
done();
});
});
test.each(['offline','online'])('should addEventListener for %p, event',(v)=>{
expect(events[v]).toBeTruthy()
})
test.each([['offline',false],["online",true]])('when %p called ,then signal value must be %p',(eventName,value)=>{
events[eventName]()
expect(service.networkStatus()).toEqual(value);
})
test.each([['offline',false],["online",true]])('when %p called,then observable must return %p',(eventName,value)=>{
events[eventName]()
service.networkStatus$.subscribe(val=>{
expect(val).toEqual(value)
})
})
});
describe('when connection value changes for signals', () => {
const events = {};
const addEventListener = jest.fn((event, callback) => {
events[event] = callback;
});
const mockDocument = { defaultView: {navigator: {onLine: false}, addEventListener } }
beforeAll(() => {
TestBed.configureTestingModule({
providers:[{provide:DOCUMENT, useValue: mockDocument}]
})
service = TestBed.inject(InternetConnectionService);
});
it('signal value must be false when offline event is called while internet is connected', () => {
events['online']()
expect(service.networkStatus()).toEqual(true);
events['offline']()
expect(service.networkStatus()).toEqual(false);
});
it('signal value must be true when online event is called while internet is disconnected', () => {
events['offline']()
expect(service.networkStatus()).toEqual(false);
events['online']()
expect(service.networkStatus()).toEqual(true);
});
it('observable value must be false when offline event is called while internet is connected', (done:any) => {
events['online']()
events['offline']()
service.networkStatus$.subscribe(val=>{
expect(val).toEqual(false)
done()
})
});
it('observable value must be true when online event is called while internet is disconnected', (done:any) => {
events['offline']()
events['online']()
service.networkStatus$.subscribe(val=>{
console.log(val);
expect(val).toEqual(true)
done()
})
});
});

17
npm/ng-packs/packages/theme-shared/src/lib/components/internet-connection-status/internet-connection-status.component.ts

@ -1,14 +1,13 @@
import { Component, inject } from '@angular/core';
import { CommonModule } from '@angular/common'
import { map } from 'rxjs';
import { InternetConnectionService, LocalizationModule } from '@abp/ng.core';
import { Component, computed, inject } from '@angular/core';
import { NgIf } from '@angular/common'
import { InternetConnectionService , LocalizationModule } from '@abp/ng.core';
@Component({
selector: 'abp-internet-status',
standalone: true,
imports:[CommonModule,LocalizationModule],
imports:[NgIf, LocalizationModule],
template: `
<div class="status-icon" *ngIf="isOffline$ | async">
<div class="status-icon" *ngIf="!isOnline()">
<i data-toggle="tooltip" title="{{ 'AbpUi::InternetConnectionInfo' | abpLocalization }}" data-placement="left" class="fa fa-circle text-blinking blink">
</i>
</div>
@ -42,7 +41,7 @@ import { InternetConnectionService, LocalizationModule } from '@abp/ng.core';
}
`]
})
export class InternetConnectionStatusComponent{
internetConnectionService = inject(InternetConnectionService)
isOffline$ = this.internetConnectionService.networkStatus$.pipe(map((val) => !val));
export class InternetConnectionStatusComponent{
internetConnectionService = inject(InternetConnectionService);
isOnline = this.internetConnectionService.networkStatus
}

Loading…
Cancel
Save