• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Angular-serwis komunikacyjny komponentów

VPS Starter Arubacloud
0 głosów
243 wizyt
pytanie zadane 7 stycznia 2021 w JavaScript przez reken Początkujący (390 p.)

Wykonuje aplikacje w Angularze jednak mam problem z przesylaniem informacji miedzy komponentami a w zasadzie komunikacji miedzy nimi.Od razu mowie ze  nie mam doswiadczenia wiec prosze o wyrozumialosc ;-) co do przedstawionego kodu jak i potendjalnych pytan.
Przedstawie tu uproszczony model zamiast wrzucac mase kodu ale problem ten sam.
Komponent First bedzie sluzyl do logowania i cos wyswietlal a komponent Second do pobierania danych  i tez cos tam wyswietlal tak sobie to wymyslilem.Stworzylem serwis Communication jak nazwa mowi do komunikacji
Kod first.component.ts
 

import { Component, OnInit } from '@angular/core';
import { CommunicationService } from '../communication.service';

@Component({
  selector: 'app-first',
  templateUrl: './first.component.html',
  styleUrls: ['./first.component.css']
})
export class FirstComponent implements OnInit {

  val_first="pierwszy komponent";
  constructor(private communication: CommunicationService) { }
  changeVal():void{
    this.communication.changeSecVal(this.val_first);
    console.log("First wartosc: " + this.val_first);
  }
  ngOnInit(): void {
  }

}

first.component.html

<p>First</p>
<button (click)="changeVal()">Wcisnij</button>

Kolejny komponent

second.component.ts
 

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-second',
  templateUrl: './second.component.html',
  styleUrls: ['./second.component.css']
})
export class SecondComponent implements OnInit {
  var_second ="wartosc";
  constructor() { }

  setVar(val:string):void{
    this.var_second = val;
    console.log("Second wartosc: " + this.var_second);
  }
  ngOnInit(): void {
  }

}

second.component.html
 

<p>Second</p>
<p>{{var_second}}</p>

Serwis
communication.serwis.ts
 

import { Injectable } from '@angular/core';
import { SecondComponent } from './second/second.component';

@Injectable({
  providedIn: 'root'
})
export class CommunicationService {

  constructor(private sec: SecondComponent) { }

  changeSecVal(val:string):void{
    this.sec.setVar(val);
    console.log("Communication wartosc: " + val);
  }
}

Moduł
app.module.ts
 

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FirstComponent } from './first/first.component';
import { SecondComponent } from './second/second.component';

@NgModule({
  declarations: [
    AppComponent,
    FirstComponent,
    SecondComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [SecondComponent],
  bootstrap: [AppComponent]
})
export class AppModule { }

Jak widac model działania, wciskam przycisk w  pierwszym komponencie i chcialbym aby w w yniku tego sygnału przekazywana informacja wykonywała/rozpoczynała cos w drugim komponencie.W tym przypadku ustawiała zmienna( to jedynie przyklad).I teraz jak powrzucałem "logi" to widze ze wartosc jest przekazywana tak jak planowąłem ale w zmienna w html komponentu second sie nie zmienia i tego nie rozumiem mimo ze logi wyswietla ze zmienna ma przekazana wartosc.Nie rozumiem dlaczego tak sie dzieje
Słowem dopowiedzenia.Jak odpalilem to bez zmian w app.module.ts to otrzymałem bład w konsoli
 

core.js:5980 ERROR NullInjectorError: 
R3InjectorError(AppModule)[CommunicationService -> SecondComponent -> SecondComponent -> SecondComponent]: 
  NullInjectorError: 
No provider for SecondComponent!

Wiec dodałem bez przekonania wpis w app.module.ts -> @NgModule-> providers[DaneComponent] i usunłą sie bład.I teraz nie ma błedu ale nie wykonuje tego w taki sposob jak bym oczekiwał.
Wydaje mi sie ze jednak to nie jest poprawne miejsce do podawania kompnentu .Miejsce providers[] chyba jest przeznaczone do podawania serwisu
Ogolnie byłbym wdzieczny jakby ktos podrzucil kilka słow wyjasnienia dlaczego to nie działa "jak powinno" albo w jaki sposob osiagnac odpowiedni efekt

1 odpowiedź

+2 głosów
odpowiedź 7 stycznia 2021 przez Tomek Sochacki Ekspert (227,510 p.)
wybrane 7 stycznia 2021 przez reken
 
Najlepsza

w ogóle namieszałeś... serwis to serwis, nie widzę za bardzo sensu wstrzykiwania do niego przez DI innego komponentu - co chciałeś tym osiągnąć? W serwisie masz pola/metody współdzielone, które potem użyją komponenty i to w komponentach wstrzyknij przez DI ten serwis. Ponad to w providers ustawia się właśnie serwisy, a nie komponenty.

serwis:
class Service {
  public name: string;
}

komponent A:
class ComponentA {
  public constructor(private service: Service) {}

  public ngOnInit(): void {
    console.log(`Komponent A: ${this.service.name}`);
  }
}

komponent B:
class ComponentB {
  public constructor(private service: Service) {}

  public ngOnInit(): void {
    console.log(`Komponent B: ${this.service.name}`);
  }
}

i wtedy w obu komponentach używasz serwisu. Serwis może być singletonem co jest w sumie najczęściej sptykane ale nie jest to konieczne, zależy co potrzebujesz zrobić.

 

I nie rob serwisu CommunicationService, to jest błędne podejście. Zrób serwisy zawierające odpowiednie elementy biznesowe, na przykład LoginService itp. Nie bój się posiadania dużej liczby serwisów, lepsze to niż wrzucać wszystko do jednego worka o nic nie mówiącej nazwie.

W komponentach potem możesz też odnosić się do serwisów, wtedy oczywiście muszą być one wstrzyknięte jako public ale to nie jest najlepsza praktyka, osobiście raczej wolę wyrażny podział między serwisem i komponentem, który odpowiednio przygotowuje dane z serwisu dla widoków ale to już kwestia preferencji.

komentarz 7 stycznia 2021 przez reken Początkujący (390 p.)
edycja 7 stycznia 2021 przez reken

Dzieki za merytoryczna odpowiedz sporo uwag, musze zatem wprowadzic zmiane.Własnie jak wyrzuciło mi bład w konsoli i zmianach   providers[]  to czulem ze chyba namieszałem w logice działania

Cel jaki chcialem osiaganc to aby metoda komponentu pierwszego uruchamiała metode komponentu2.I dzieki temu ze zrobilem wstrzykniecie komponentu do serwisu ( wiem dziwne, tonący przytwy cie chwyta;-) ) mialem dostep do metod komponentu ktore uruchamiały jego działanie.
Biorac pod uwage powyzszy cel nadal mam pytanie poniewaz chciałem zeby pierwszy komponent tak jak mowilem odpowiadał za logowanie a drugi za pobieranie danych/zapisywanie w bazie. Wiec potrzebuje to tego chocby nazwy uzytkownika przeslanego z A do B .Biorac pod uwage powyzsze uwagi to zrobilbym to tak:

export class Service {
    public nameUser: string = 'user';
    public userIn: boolean = false;
   
  setName(name:string){
    this.nameUser = name;
    this.userIn = true;
  }
  constructor() {} 

}

czyli serwis przechowuje nazwe i flage ( czy uzytkownik wczytany).I teraz komponentA wczytuje go. Jesli wszystko ok komponentA powinien zmienic nazwe na aktualna i zmodyfikowac flage wejscia a komponent B nasluchuje, jesli flaga zmieniona pobieram nazwe i zapisuje w bazie danych np date logowania .
Własnie komunikacja na tych dwoch wartosciach+nasluchiwanie componentu B stanowi problem
Wprowadzilem zmiany powyzsze i komponenty pobieraja nazwe/maja dostep do nameUser  i super ale nie moge go zmodyfikowac przez komponent logujacy. Jest to chyba tylko komunikacja z serwisu do kazdego z komponentow dlatego napisalem setera liczac ze ustawie z pierwszego komponentu zmienne a drugi pobierze zmienione wartosci ale nadal chyba cos nie do konca łape
 

1
komentarz 7 stycznia 2021 przez Tomek Sochacki Ekspert (227,510 p.)
a dlaczego w ogóle to komponenty mają odpowiadać za logowanie i pobieranie jakiś danych? Od tego są właśnie serwisy. Zrób serwis np. UserService, który przechowa dane o zalogowanym użytkowniku oraz LoginService, który zawiera logikę związaną z logowaniem, wylogowaniem itp. Następnie komponenty niech po prostu pobierają sobie asynchronicznie dane z UserService. User będzie tutaj jakimś Observable, na który po prostu pozapinasz się w odpowiednich komponentach. Zmiana statusu usera zostanie wtedy od razu spropagowana na wszystkie komponenty, które tego używają (np. wylogowanie itp.).

Natomiast co do zapisu do bazy to w zasadzie na froncie w ogóle Cię to nie interesuje, ty masz metodę np. createUser, która konsumuje jakiś endpoint POST, i to już backend wie co z tym zrobić, front nie powinien interesować się sposobem zapisu usera itp.

Przede wszystkim musisz jeszcze raz podejść do tematu i na spokojnie sobie podziel projekt na logiczne fragmenty. Serwis w żadnym razie nie powinien wywoływać żadnej metody komponentu, to komponenty powinny być zapięte na odpowiednie pola/metody serwisu. Tak na prawdę dobrze jest też pisać tak, aby serwis nie miał świadomości kto w ogóle chce z niego korzystać, serwis powinien udostępniać tylko określony interfejs, który konsumują komponenty lub inne serwisy.
komentarz 7 stycznia 2021 przez reken Początkujący (390 p.)
Ok to cenna wskazowka w zasadzie to zastanawiałem sie czy to przez serwis nie zrobic ale jak widziałem jakis template na stronie Angulara i byl  zrobiony na komponencie to dlatego moze sie tak przy nim upierałem.
Jeszcze jedno ostatnie pytanie bo teraz to co powiedziales wiele mi wyjasnilo "odosnie serwis udostepnia komponenty zaciagaja" czyli taka jednokierunkowe udostepnianie danych a jak sprawa ma sie miedzy serwisami? Czy moga sie komunikowac?W ogole?dwukierunkowo?Teraz mam juz 2 serwisy w projekcie narazie nie jest mi potrzebna komunikacja miedzy nimi ale pytam na przyszlosc
komentarz 7 stycznia 2021 przez Tomek Sochacki Ekspert (227,510 p.)
Jasne, wszystko może komunikować się ze wszystkim... serwis to zwykła klasa, która udostępnia jakieś metody i pola. Jak chcesz współdzielić jakąś wartość między inne serwisy/komponenty to musi to być pole/metoda public. Jeśli chcesz dodatkowo aby wszystko było asynchroniczne i ładnie reagowało na zmiany itp. to po prostu zrób sobie observable, to najczęstsza praktyka i bardzo wygodna. Osobiście staram sie wszędzie gdzie się da pracować właśnie z asynkiem, daje to duże możliwości.

Chociaż jeśli potrzebujesz, aby serwisy komunikowały się dwukierunkowo, to pytanie czy nie potrzebujesz czasem jakiegoś dodatkowego, trzeciego serwisu dla nich wspólnego? Pytanie dlaczego oba serwisy są tak powiązane biznesowo, że muszą mieć taką komunikację i czy nie powinien to być może jednak albo jeden serwis, albo jak wspomniałem, dwa z dodatkowym trzecim?

Oczywiście wszystko zależy zawsze od konkretnego przypadku.
komentarz 7 stycznia 2021 przez reken Początkujący (390 p.)

Jeszcze raz wielkie dzieki za pomoc i wskazowki.
return (The best answer + (głos++))  smiley

Podobne pytania

0 głosów
2 odpowiedzi 297 wizyt
pytanie zadane 4 października 2019 w JavaScript przez daniel1806 Obywatel (1,780 p.)
0 głosów
1 odpowiedź 403 wizyt
pytanie zadane 4 listopada 2020 w C# przez assassin Gaduła (3,260 p.)
0 głosów
2 odpowiedzi 259 wizyt
pytanie zadane 18 listopada 2019 w Nasze projekty przez obl Maniak (51,280 p.)

92,453 zapytań

141,262 odpowiedzi

319,088 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...