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

Angular przekazywanie zmiennej

VPS Starter Arubacloud
0 głosów
771 wizyt
pytanie zadane 19 marca 2020 w JavaScript przez michal_php Stary wyjadacz (13,700 p.)

Cześć.

Prubuje przekazać zmienna z componentu rodzica do dziecka ,ale nie wiem co robię źle ,że component dziecko jej nie widzi: ( komentarzami opisałem z kąt do kąt wysyłam zmienną)

component rodzic:

import { Component, OnInit } from '@angular/core';
import {AuthenticationService} from '../../../_services/authentication.service';
import {Router} from '@angular/router';
import {UserService} from '../../../_services/user.service';
import {CalendarService} from '../../../_services/calendar.service';
import {first} from 'rxjs/operators';
import {Calendar} from '../../../_model/calendar';
import {ValueService} from '../../value.service';

@Component({
  selector: 'app-calendar',
  templateUrl: './calendar.component.html',
  styleUrls: ['./calendar.component.less']
})
export class CalendarComponent implements OnInit {
  actualDay: number;
  monthNumber: number;
  month: string;
  year: number;
  allDays: Calendar[];
  start: Calendar[];
  load = true;

  constructor(
    private calendarService: CalendarService,
    private router: Router,
    private valueService: ValueService
  ) {
    const data = new Date();
    this.actualDay = data.getDate();
    this.monthNumber = data.getMonth() + 1;
    this.year = data.getFullYear();
  }

  ngOnInit(): void {
    this.getAllDays();
  }

  getAllDays() {
    this.calendarService.getNumberDays().pipe(first()).subscribe(days => {
        this.allDays = days;
    })
  }


  // tutaj przekazuje liczbę i z tond przekazuje ją da service
 // metoda getNexDay jest uruchomiana poprzez klikniecie button z odpowiadaniom wartością
  getNexDay(day : number) { 
    this.valueService.nextDay(day);
  }

}

service:

import { Injectable } from '@angular/core';
import {Subject} from 'rxjs';

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

  dayNext$ = new Subject<number>();

  nextDay(day : number) {
    this.dayNext$.next(day);
    console.log(day); // tutaj działa i widzi tą zmienna
  }
}

i component dziecko:

import { Component, OnInit } from '@angular/core';
import {CalendarService} from '../../../../_services/calendar.service';
import {first} from 'rxjs/operators';
import {Task} from '../../../../_model/task';
import {ValueService} from '../../../value.service';
import {Subscription} from 'rxjs/';

@Component({
  selector: 'app-task',
  templateUrl: './task.component.html',
  styleUrls: ['./task.component.less']
})
export class TaskComponent implements OnInit {
  tasks: Task[];
  nextDay: Subscription;
  findNexDay: number;

  constructor(
    private calendarService: CalendarService,
    private valueService: ValueService
  ) { }

  ngOnInit(): void {
    this.getTasks();
  }

  getTasks() {
    this.calendarService.getTasks().pipe(first()).subscribe(task=>{
      this.tasks = task;
    })
  }

 // tutaj staram się pobrać zmienną ale nic nie widzi
  getNextTask() {
      this.nextDay = this.valueService.dayNext$.subscribe((day)=>{
      this.findNexDay = day;
    })
console.log(this.findNexDay); // tutaj już właśnie nie widzi i nie chce poprać zmiennej
  }

}

Z góry bardzo dziękuje za pomoc lub wskazówkę.

1 odpowiedź

+2 głosów
odpowiedź 19 marca 2020 przez Aisekai Nałogowiec (42,190 p.)
edycja 19 marca 2020 przez Aisekai
  getNextTask() {
      this.nextDay = this.valueService.dayNext$.subscribe((day)=>{
      this.findNexDay = day;
    })
console.log(this.findNexDay); // tutaj już właśnie nie widzi i nie chce poprać zmiennej
  }
}

Bo subscribe działa asynchronicznie, a JS jest językiem jednowątkowym. Więc odwołać się do tej zmiennej, powinieneś wewnątrz callbacku subscribe.  Podobna sytuacja jest gdy robisz sobie np. setTimeout(()=>{}, 0), wtedy mimo że timeout jest równy 0, to i tak to się wywoła dopiero w chwili "gdy nic innego się nie będzie robiło".

Dwa, ta metoda jest zrypana trochę, bo subscribe'ujesz za każdym razem gdy ją wywolujesz. I o ile takie coś działa (i jest konieczne) podczas pobierania danych z serwera (żądanie-odpowiedź), o  tyle teraz za każdym razem gdy wywołujesz tą funkcję, tworzysz nowy callback. Po pierwsze, nie unsubscribe'ujesz tego, po drugie masz memory leak. 

komentarz 19 marca 2020 przez michal_php Stary wyjadacz (13,700 p.)
A jak byś polecał to zrobić ?
komentarz 19 marca 2020 przez Aisekai Nałogowiec (42,190 p.)
A co chcesz osiągnąć?
komentarz 19 marca 2020 przez michal_php Stary wyjadacz (13,700 p.)
Chce przekazać tylko zmienną z rodzica do dziecka. A czy można by coś zrobić aby ta moja metoda była poprawna ?
komentarz 19 marca 2020 przez michal_php Stary wyjadacz (13,700 p.)

Zrobiłem coś takiego. Ale jak mam zrobić tego callback ?

Dodałem unsubscribe. Czy teraz było by lepiej ?

import { Component, OnInit, OnDestroy } from '@angular/core';
import {CalendarService} from '../../../../_services/calendar.service';
import {first} from 'rxjs/operators';
import {Task} from '../../../../_model/task';
import {ValueService} from '../../../value.service';
import {Subscription} from 'rxjs/';

@Component({
  selector: 'app-task',
  templateUrl: './task.component.html',
  styleUrls: ['./task.component.less']
})
export class TaskComponent implements OnInit, OnDestroy {
  tasks: Task[];
  nextDay: Subscription;
  findNexDay: number;

  constructor(
    private calendarService: CalendarService,
    private valueService: ValueService
  ) { }

  ngOnInit(): void {
    this.getNextTask();
  }

  getNextTask() {  // nie za bardzo wiem jak zrobić tego callback
     this.nextDay = this.valueService.dayNext$.subscribe((task)=>{
       this.findNexDay = task;
     })
    console.log(this.nextDay);
  }

  ngOnDestroy(): void { // to dodałem 
    if (this.nextDay){
        this.nextDay.unsubscribe();
    }
  }

}

 

komentarz 19 marca 2020 przez Aisekai Nałogowiec (42,190 p.)

Dobra. Zacznijmy od tego. Callback, to jest funkcja którą podsyłasz, która ma zostać wywołana w "pewnej chwili" (nie wywołujesz jej od razu, tylko w twoim przypadku, subject przechowuje sobie wszystkie funkcje i w chwili gdy używasz next, wywołuje je jako parametr podając wartość którą przekażesz w next). 

I teraz tak. Masz kilka opcji do komunikacji między komponentami. Jedną z nich jest @Input i @Output. Drugą jest to co teraz masz, czyli przez serwis. Ja bym to zrobił tak, że w ngOnInit, wywołałbym funkcję taką:

 getNextTask() {  // nie za bardzo wiem jak zrobić tego callback
     return this.nextDay = this.valueService.dayNext$.subscribe((task)=>{
       this.findNexDay = task;
     })
  }

Jako pole w klasie dodałbym:

subscriptions = new Subscription()

W ngOnInit:

this.subscriptions.add(this.getTasks());

W ngOnDestroy:

this,subscriptions.unsubscribe();

I teraz gdy chcesz "przekazać" wartość między komponentami, to np jak masz inny komponent który ma przycisk: "Następne zadania", to podpinasz do niego zachowanie które spowoduje, że w serwisie zostanie wywołana metoda .next() z nowymi Taskami (Task[]). 

I teraz tak:

gdy masz metodę valueService.dayNext$.subscribe(), to tak jak wcześniej podałem, jako parametr podajesz funkcję która ma zostać wywołana. A jako parametr, dostaniesz taki typ i taką wartość, jaka np zostanie przesłana do subject.

Podobne pytania

0 głosów
1 odpowiedź 105 wizyt
pytanie zadane 15 marca 2020 w JavaScript przez michal_php Stary wyjadacz (13,700 p.)
0 głosów
0 odpowiedzi 101 wizyt
pytanie zadane 7 kwietnia 2018 w JavaScript przez pulson666 Stary wyjadacz (12,560 p.)
0 głosów
1 odpowiedź 204 wizyt
pytanie zadane 18 maja 2017 w JavaScript przez crova Użytkownik (940 p.)

92,453 zapytań

141,262 odpowiedzi

319,086 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!

...