Angualr Flex-Layout Library에서 mediaOvserver라는게 있단다.
그거는 아래처럼 설치가 가능하며, app.module.ts 파일에 집어넣어서 쓰면 된단다.
npm install @angular/flex-layout
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { FormsModule } from "@angular/forms";
import { AppComponent } from "./app.component";
import { FlexLayoutModule } from "@angular/flex-layout";
@NgModule({
imports: [BrowserModule, FormsModule, FlexLayoutModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
})
export class AppModule {}
MediaObserver Service는 mediaQuery changes를 감지하는 Observable인데, isActive() 란ㄴ 메소드가 현재 mediaQuery가 active하는지를 체크도 해주는 기능을 가지고 있단다.
MediaObserver는 2개의 API가 있단다.
1. asObservable(): Ovservable<MediaChange>
2. isActive(query: string): boolean
우리는 이 서비스를 사용하기 위해서, 앵귤러의 의존성 주입(DI)를 통해서 MediaOvserver를 constructor parameter에 집어넣을 것이란다.
코드를 보자꾸나.
import { Component, OnDestroy, OnInit } from '@angular/core';
import { MediaChange, MediaObserver } from '@angular/flex-layout';
import { Subscription } from 'rxjs';
import { distinctUntilChanged } from 'rxjs/operators';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements Oninit, OnDestroy {
title = 'Angular Flex-Layout';
/**
*
*
* @param mediaObserver
*/
constructor(public mediaObserver: MediaObserver) {}
private mediaSubscription!: Subscription;
private activeMediaQuery: string = '';
ngOnInit(): void {
const getAlias = (MediaChange: MediaChange[]) => {
return MediaChange[0].mqAlias;
};
this.mediaSubscription = this.mediaObserver
.asObservable()
.pipe(
distinctUntilChanged(
(x: MediaChange[], y: MediaChange[]) => getAlias(x) === getAlias(y)
)
)
.subscribe((chage) => {
chage.forEach((item) => {
this.activeMediaQuery = item
? `'${item.mqAlias}' = (${item.mediaQuery})`
: '';
if (item.mqAlias === 'md') {
this.loadMobileContent();
}
console.log('activeMediaQuery', this.activeMediaQuery);
});
});
}
ngOnDestroy(): void {
this.mediaSubscription.unsubscribe();
}
loadMobileContent {
console.log('load mobile content');
// Do something special since the viewport is currently
// using mobile display sizes
}
}
}
}
현재 Angular Flex-Layout의 wiki page는 좀 오래된 예제란다. media$ observable이 mediaObserver로 대체가 되었단다.
change detection이 일어날 때, 약간의 버그가 나오는데, 결과가 중복되는 경우가 있단다.
그래서 위의 코드에서, distinctUntilChanged() RxJS를 operator를 써서, 중복을 없앴단다.
sm, lt-md, lt-lg, lt-xl, gt-xs 등등, 대부분의 사이즈를 알 수 있단다.
그래서 이걸 어떻게 쓸 수 있을거 같으니?
애플리케이션을 디자인할 때, 우리의 UI를 효과적 사용하기 위해서 우리는 스크린 뷰 사이즈를 알아야 한단다.
뭐, 숨기거나 조작하거나 이럴 때 쓸 수 있겠지
<div fxLayout="row" fxLayoutGap="10px">
<div fxFlex="1 0 10" *ngIf="mediaObserver.isActive('md')"
id="boxone" style="background: red;">Box One</div>
<div fxFlex="1 0 10" id="boxtow" style="background: blue;">Box Two</div>
</div>
browser가 md 사이즈에 오면, 2번째 줄 div는 사라지게 만들 수 있겠지.
mediaObserver를 HTML에 사용하기 위해선, get() 메소드로 접근을 할 수 있게 해줘야해
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit, OnDestroy {
title = 'Angular Flex-Layout';
get media() {
return this.mediaObserver;
}
...
}
또 다른 예제를 들고와보자꾸나
import { Component, OnInit } from '@angular/core';
import { MediaChange, MediaObserver } from '@angular/flex-layout';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {
constructor(private mediaObserver: MediaObserver) {}
cols: Observable<any> | undefined;
ngOnInit(): void {
const grid = new Map([
['xs', 1],
['sm', 2],
['md', 3],
['lg', 4],
['xl', 5],
]);
this.cols = this.mediaObserver.asObservable().pipe(
map((change: MediaChange[]) => {
console.log(change[0]);
console.log(grid.get(change[0].mqAlias));
return grid.get(change[0].mqAlias);
})
);
}
위에 코드는 MediaObserver를 constructor에 주입을 했으며, 새로운 grid라는 친구를 만들어서, mediaObserver를 asObservable()을 이용해서 observable로 세팅을 했단다.
그래서 browser가 resize될 때, breakpoint를 mqAlias를 통해서 받을 수 있단다. 그리고, 이 전에 선언한 grid에서 get 메소드를 호출해 cols 변수에 집어넣었단다.
<mat-grid-list rowHeight="1:1" [cols]="cols | async" gutterSize="6px">
<mat-grid-tile> {{1}} </mat-grid-tile>
<mat-grid-tile> {{2}} </mat-grid-tile>
<mat-grid-tile> {{3}} </mat-grid-tile>
<mat-grid-tile> {{4}} </mat-grid-tile>
<mat-grid-tile> {{5}} </mat-grid-tile>
</mat-grid-list>
HTML에서 Angular Material grid list component를 사용해보았으며, async pipe를 통해 observable을 구독했단다.
그래서 browser 사이즈가 줄어들었을 때, 이를 캐치하여 원하는 값을 넣을 수 있겠지.
이렇듯 mediaObserver를 쓰면, 우리의 애플리케이션이 viewport 변화를 알아내어서 우리가 원하는 동작을 하도록 해보았단다.
만약, 휴대폰 전용 웹뷰 코드에다 해당 mediaObserver를 잘 버무리면, PC에서도 똑같은 서비스를 제공할 수 있겠지 ?
이상 Angular Flex-Layout using MediaObserver였습니다. ^_^
'Web + APP > Angular' 카테고리의 다른 글
Renderer2 in Angular 12 (Why not ElementRef ?) (0) | 2021.09.25 |
---|---|
iOS 한글 buffer 문제 (1) | 2021.09.11 |
RxJS 구독해제 패턴 심화편 (3) | 2021.06.26 |
Async Pipe 뜯어먹기 (4) | 2021.05.30 |
RxJS가 해결하려고 했던 문제 3 (6) | 2021.05.20 |