Baza wiedzy
Jednokierunkowe wiązanie danych z atrybutem komponentu wydaje się w Angular proste. Są jednak sytuacje, jak w przypadku komponentu img, do którego chcemy załadować obrazek dynamicznie i asynchronicznie, że wymaga to użycia kilku dodatkowych mechanizmów.
Problem postawiony w temacie wydaje się oczywisty. Wystarczy w szablonie napisać tak:
<img [src]="imgSrc" />
a w klasie komponentu:
private imgSrc = '/obrazek.jpg';
A co jeżeli wartośćimgSrc
nie jest od razu znana - np. pobieramy ją
z serwera? Wtedy sprawa też wydaje się prosta - otrzymujemy z serwera url obrazka i tą wartość podstawiamy doimgSrc
.
Wyglądałoby to mniej więcej tak, że piszemy w klasie serwisowej metodę do pobierania urla obrazka:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class ImgUrlService {
constructor(private http: HttpClient) { }
getImageUrl(): Observable<string> {
return this.http.get<string>('url_do_metody_restowej');
}
}
A w komponencie:
export class TestComponent implements AfterViewInit {
private imgSrc = '/obrazek.jpg';
constructor(private imgUrlService: ImgUrlService) {}
ngAfterViewInit(): void {
this.imgUrlService.getImageUrl().subscribe(imgUrl => {
this.imgSrc = imgUrl;
});
}
}
Powyższe będzie działać pod warunkiem, że na serwerze znajduje się dodatkowo metoda, która na podstawie przysłanego wcześniej url-a jest w stanie odesłać zawartość obrazka.
Co jeśli takiej metody nie mamy, a zamiast tego istnieje metoda, która przysyła obrazek w postaci zakodowanej, np. base64? Wówczas po stronie przeglądarki musimy wykonać pewne czynności, zanim taki obrazek będzie mógł być użyty przez przeglądarkę w elemencieimg
. W tym celu musimy zmodyfikować przede wszystkim metodę usługową:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { DomSanitizer } from '@angular/platform-browser';
import { SafeUrl } from '@angular/platform-browser/src/security/dom_sanitization_service';
@Injectable()
export class ImgUrlService {
constructor(private http: HttpClient, private sanitizer: DomSanitizer) { }
getImageUrl(): Observable<SafeUrl> {
return this.http.get('url_do_metody_restowej', {
responseType: 'blob'
}).map(response => {
return this.sanitizer.bypassSecurityTrustUrl(URL.createObjectURL(response));
});
}
}
Na podstawie przesłanego ciągu bajtów tworzymy specjalny url, który wskazuje na obiekt w pamięci. Dodatkowo, aby Angular nie protestował, że utworzony w ten sposób url jest niebezpieczny, musimy wywołać metodębypassSecurityTrustUrl
.
Teraz czas na zmianę w szablonie komponentu, w którym przy okazji skorzystamy z interesującego filtruasync
, aby Angular wiedział, że podana wartość jest pobierana asynchronicznie.:
<img [src]="imgSrc | async" />
Filtr ten wymaga, aby podane wyrażenie było typuPromise
, alboObservable
. Ponieważ chcemy być nowocześni, w naszym przypadku skorzystamy zObservable
:
export class TestComponent implements AfterViewInit {
private imgSrc: Observable<SafeUrl>;
constructor(private imgUrlService: ImgUrlService) { }
ngAfterViewInit(): void {
this.imgSrc = this.imgUrlService.getImageUrl();
}
}
Widać, że kod komponentu zrobił się przyjemniejszy, mamy proste przypisanie wyniku zwracanego przez metodęgetImageUrl
do polaimgSrc
. Niestety powyższy kod generuje pewien problem. Zanim metodagetImageUrl
zwróci wartość, "obserwabla"imgSrc
nie będzie zawierała wartości, a co za tym idzie przeglądarka spróbuje pobrać obrazek z adresu http://localhost:4200/null. Raczej nie mamy zasobu o takim adresie, więc w konsoli przeglądarki pojawi się błąd. Dla użytkownika będzie on niewidoczny, niemniej nie wygląda to najlepiej. Źródłowym problemem jest tutaj brak możliwości utworzenia obiektu typuObservable
z inicjalną wartością.
Na szczęście biblioteka rxjs, z której korzysta Angular, zawiera szereg definicji klas, z których jedna jest dla nas interesująca -BehaviorSubject
. Jest to o tyle ciekawy obiekt, że po pierwsze działa jak obiektObservable
, czyli taki, do którego możemy się podłączyć metodąsubscribe
i oczekiwać na wynik. Po drugie działa jak "zlew", do którego możemy sekwencyjnie wlewać pewne wartości, które będą odbierane w metodziesubscribe
- również sekwencyjnie. Jeżeli do tej pory nie miałeś(aś) wiele wspólnego z biblioteką rxjs, ale wiesz jak działają "obietnice" (Promise
), to najważniejsza różnica o której musisz wiedzieć to fakt, że obiekty typuObservable
mogą generować wiele wartości w odróżnieniu odPromise
, które zawsze generuje tylko jedną wartość. Podobne zachowanie doBehaviorSubject
ma obiektSubject
. Jak można wnioskować na podstawie nazw, klasaBehaviorSubject
rozszerza klasęSubject
właśnie poprzez możliwość zdefiniowania inicjalnej wartości. To nam załatwia w/w problem z null-em. W tym celu stworzymy sobie obiektBehaviorSubject
z jakimś inicjalnym obrazkiem, najlepiej tzw. pustym obrazkiem, którego reprezentację można sobie wygenerować w wielu dostępnych w internecie generatorach.
Ostatecznie nasz komponent będzie wyglądać tak:
export class TestComponent implements OnInit, AfterViewInit {
private imgSrc: BehaviorSubject<SafeUrl>;
constructor(private imgUrlService: ImgUrlService) { }
ngOnInit(): void {
this.imgSrc = new BehaviorSubject('data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=');
}
ngAfterViewInit(): void {
this.imgUrlService.getImageUrl().subscribe(imgUrl => {
this.imgSrc.next(imgUrl);
});
}
}
Jak widać używamy metody next, za pomocą której "wlewamy" do naszego "zlewu" kolejną wartość, która zostanie użyta przez Angular-a do zasilenia atrybutu src.
W powyższym przykładzie pobieramy obrazek tylko jednokrotnie, po zainicjowaniu naszego komponentu, ale nic nie stoi na przeszkodzie, aby wywołaćthis.imgSrc.next
w innym miejscu.
Zainteresował Cię ten wpis?
Chcesz dowiedzieć się więcej?
Michał Gierwatowski
Programista wszechstronny, od języka Progress4GL począwszy, przez Javę, na TypeScripcie kończąc. Ponad piętnastoletnie doświadczenie w wytwarzaniu różnego rodzaju systemów informatycznych. Ostatnio interesuje się nowinkami w ekosystemie JavaScript/node.js
Michał.Gierwatowski(at)monolit-it.pl
Zobacz wszystkie artykuły danego autora »Ostatnie:
Najpopularniejsze TAGi:
Tagi
W swoim czasie linia produktowa stacjonarnych komputerów biznesowych Dell OptiPlex dzieliła się na kilka różnych modeli, a te z kolei podzielono na dodatkowe modele w danej linii produktowej opartej na niezbyt jasnej numeracji. Dla osoby nie obeznanej z nazewnictwem był to spory problem aby odnaleźć się w gąszczu dostępnych wersji.
O rozwiązaniach IoT pisze się najczęściej w kontekście przemysłu 4.0, czy inteligentnych miast. Rozwiązanie NetQM for IoT jest z sukcesem wdrażane w jednostkach samorządu terytorialnego jako System Monitorowania i Sterowania Siecią Kanalizacji Ciśnieniowej.
Firma Dell od samego początku charakteryzowała się dużą dbałością w kwestii zakresu gwarancyjnego dla swoich produktów. Nie inaczej wygląda sytuacja dziś i można zaryzykować stwierdzenie, że jest to niejako wyróżnik tej organizacji na tle jej konkurencji.
W ostatnim czasie pojawiło się kilka ciekawych rozwiązań zastosowanych przez producentów notebooków. Większość z nich jest jak najbardziej dostosowana do potrzeb potencjalnych użytkowników i wydaje się, że trafi prosto pod strzechy.
Od dawna mówi się o usługach czy przemyśle 4.0 w kontekście biznesu. Coraz częściej jednak rozmawia się również o usługach 4.0 skierowanych do samorządów... Przykład? System monitorowania i sterowania siecią kanalizacji niskociśnieniowej w oparciu o rozwiązanie NetQM for IoT.
Miniony rok, podobnie jak poprzednie lata, cechował się dużą zmiennością i zawirowaniami w różnych sferach naszego życia, w tym między innymi dotyczącymi cyberbezpieczeństwa. Znana firma analityczno-badawcza jaką jest Gartner, wykazała siedem głównych trendów związanych z bezpieczeństwem IT w roku 2022.
Bezpieczeństwo odmieniane przez wszystkie przypadki jest obecnie jedną z najczęściej podnoszonych kwestii w świecie IT. Dodatkowo w erze postpandemicznej, która spowodowała przejście do pracy zdalnej lub hybrydowej, doszło do decentralizacji ludzi i maszyn, a co za tym idzie, wzmogło konieczność skutecznej kontroli dostępu uprzywilejowanego.
Jeden z naszych klientów zwrócił się do nas w sprawie przedstawienia propozycji zakupu urządzeń, które umożliwiłyby przekształcenie w formę cyfrową jego bardzo dużych zasobów bibliotecznych.
Wzmocnione notebooki czy tez tablety to dosyć specyficzny wycinek rynku IT. Sprzęt ten często charakteryzuje się gorszymi parametrami technicznymi niż topowe produkty (choć to tez powoli ulega zmianie), ale ma coś czego typowo biznesowy sprzęt nie ma i mieć nie będzie.