Angular – jak zmienić styl CSS komponentu-dziecka w odpowiedzi na zdarzenie na elemencie w komponencie-rodzicu?

0

Obłaskawiania Angulara ciąg dalszy (po tym problemie).

Czytam aktualnie o komunikacji między komponentem-rodzicem a komponentem-dzieckiem, ale do tej pory nie zauważyłem, by któryś znaleziony przeze mnie przypadek opisywał dokładnie mój problem. Ten problem jest, wydaje się, w pewnym sensie odwrotny do wcześniej opisywanego przeze mnie na naszym forum problemu: Angular – jak zmienić styl CSS rodzica w reakcji na zdarzenie na dziecku?

Załóżmy, że mamy dwa komponenty, rodzica i dziecko:

parent.component.html

<li>
  <app-child-component></app-child-component>
</li>

child.component.html

<div></div>

Chciałbym w odpowiedzi na zdarzenie mouseover na elemencie <li> w komponencie-rodzicu zmienić styl CSS elementu <div> w komponencie <app-child-component>.

Myślę, że w rzeczywistym kodzie za zmianę stylu odpowiadałaby funkcja w JS; referencja do elementu do zmiany byłaby przekazywana do niej w parametrze. Jeśli jednak jest lepszy sposób, lub tego nie można wykorzystać, chętnie spróbuję.

1

Na początku przemyślałbym czy element <li> nie powinien być w child.component.html (enkapsulacja).
Jeżeli faktycznie musi być w parent.component.html jest wiele sposobów żeby to zrobić.
Oto jeden z nich:

parent.component.html

<li (mouseover)="child.enableStyle()" (mouseleave)="child.disableStyle()">
    <app-child #child></app-child>
</li>

child.component.html

<div [class.superstyle]="superstyle">Some text here...</div>

child.component.ts

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

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent {

  superstyle: boolean = false;

  enableStyle() {
    this.superstyle = true;
  }

  disableStyle() {
    this.superstyle = false;
  }

}

child.component.css

.superstyle {
    color: red;
}
0

Może nie konkretnie odpowiedź co do stylu, ale ogólnie reakcja 'rodzica' na zdarzenie w dziecku wywoływana jest za pomocą Output'u i EventEmitter'a w dziecku i nasłuchiwanie tego w rodzicu

https://angular.io/guide/component-interaction#parent-listens-for-child-event

0

@lookacode1: być może Twój sposób by działał, ale zanim spróbuję, mam jedną wątpliwość: używasz template reference variable. Nie zaznaczyłem tego (a chyba powinienem, przepraszam), że u mnie element <li> będzie w pętli, będzie generowany kilka razy dla swojego rodzica <ul>. Jego deklaracja w rzeczywistym kodzie wygląda podobnie do tego:

<li *ngFor="let something of arrayOfSomethings">
  ...
</li>

Z uwagi na to oraz na dokumentację Angulara dot. template reference variables nie jestem pewien, czy to będzie dobry sposób. W dokumentacji stoi, że:

The scope of a reference variable is the entire template. So, don't define the same variable name more than once in the same template as the runtime value will be unpredictable.

Chyba że nie rozumiem, co dokładnie mają deweloperzy na myśli w tym cytacie?


@froziu: dziękuję, wszystko może się kiedyś przydać. :)

0

Dlatego @lookacode1 Ci poprawnie zauważył, że jeśli nie masz konkretnego powodu, tworzy się to tak:

parent.component.html


<app-child-component></app-child-component>

child.component.html
<li>
<div></div>
</li>

(wyrzuciłem li do komponentu child)
zamiast tak jak Ty:

parent.component.html

<li>
  <app-child-component></app-child-component>
</li>

child.component.html

<div></div>

więc powinno być:

<app-child 
#child
*ngFor="let item of items"
 (mouseover)="child.enableStyle()" 
(mouseleave)="child.disableStyle()">
</app-child>

Więc masz tego tempa osobno (niezależnego) dla każdego child'a.

0

Jesli juz ci nie pasuje wrzucenie do child tak jak pokazal @froziu co IMHO jest ok to mozesz zrobic tak jak napisal @lookacode1 z tym ze wtedy jako ze elementy masz w ngFor po prostu do mouseover / mouseleave bedziesz przekazywal index array-a i potem twoj #child to bedzie QueryList gdzie szukasz sobie komponent ktory ma wlasie taki index.

Choc nie jest to zbytnio ok to napisalem ci to tylko tak zebys wiedzial jak to mozna inaczej zrobic

0
Silv napisał(a):

@lookacode1: być może Twój sposób by działał, ale zanim spróbuję, mam jedną wątpliwość: używasz template reference variable. Nie zaznaczyłem tego (a chyba powinienem, przepraszam), że u mnie element <li> będzie w pętli, będzie generowany kilka razy dla swojego rodzica <ul>. Jego deklaracja w rzeczywistym kodzie wygląda podobnie do tego:

<li *ngFor="let something of arrayOfSomethings">
  ...
</li>

Z uwagi na to oraz na dokumentację Angulara dot. template reference variables nie jestem pewien, czy to będzie dobry sposób. W dokumentacji stoi, że:

The scope of a reference variable is the entire template. So, don't define the same variable name more than once in the same template as the runtime value will be unpredictable.

Chyba że nie rozumiem, co dokładnie mają deweloperzy na myśli w tym cytacie?

Tak też zadziała moim sposobem (bo jest *ngFor, który tworzy nowy template scope).

0
froziu napisał(a):

Dlatego @lookacode1 Ci poprawnie zauważył, że jeśli nie masz konkretnego powodu, tworzy się to tak:

parent.component.html

<app-child-component></app-child-component>

child.component.html

<li>
<div></div>
</li>

(wyrzuciłem li do komponentu child)

Wydaje się móc działać... Ale w ten sposób <ul> jest w jednym komponencie, a <li> w drugim. Wydaje mi się to niestandardowe... podatne na błędy bardziej niż moje podejście.

więc powinno być:

<app-child 
#child
*ngFor="let item of items"
 (mouseover)="child.enableStyle()" 
(mouseleave)="child.disableStyle()">
</app-child>

Więc masz tego tempa osobno (niezależnego) dla każdego child'a.

Nie bardzo rozumiem. Przecież <app-child> będzie w rodzicu, więc zmienna będzie stworzona w rodzicu tyle razy, ile pętla przebiegnie. UPDATE: A, już zrozumiałem. :) Będzie w dziecku. Więc pozostaje jeszcze moja wątpliwość z powyżej.


marcio napisał(a):

Jesli juz ci nie pasuje wrzucenie do child tak jak pokazal @froziu co IMHO jest ok to mozesz zrobic tak jak napisal @lookacode1 z tym ze wtedy jako ze elementy masz w ngFor po prostu do mouseover / mouseleave bedziesz przekazywal index array-a i potem twoj #child to bedzie QueryList gdzie szukasz sobie komponent ktory ma wlasie taki index.

Nie zrozumiałem. Ale jeszcze będę próbować.


lookacode1 napisał(a):

Tak też zadziała moim sposobem (bo jest *ngFor, który tworzy nowy template scope).

Hm. Nie wiedziałem, że *ngFor tworzy nowy zakres szablonu. Nie zauważyłem o tym wzmianki – będę musiał przejrzeć jej dokumentację. Ale nadal – przecież zmienna będzie (według Twojego rozwiązania) tworzona w rodzicu, więc to rodzic będzie mieć wiele jej egzemplarzy.


PS. Mam wrażenie, że Wy mówicie nawet dobrze, tylko ja gubię się w Angularze. A myślałem, że już nie będzie tyle czytania teorii co przedtem. ;)

0

Minęło trochę czasu i, niestety, obecnie nie jestem w stanie powiedzieć, czy mój rzeczywisty problem został rozwiązany, czy nie. W działaniu aplikacji nie zauważyłem nic, co by on nim świadczyło. Mój przykład z pierwszego posta jest czymś na kształt minimal working example, a więc abstrakcją rzeczywistego problemu – i trudno mi na jego podstawie przypomnieć sobie, o co chodzi. Przepraszam.

Dla ścisłości powiem, co udało mi się odczytać z kodu, który napisałem. Podzieliłem listę HTML na sposób, jaki wspomnieliście: element <ul> jest w komponencie-rodzicu, a element <li> w komponencie-dziecku. Poza tym użyłem zdarzenia mouseenter, by wywołać funkcję JS w reakcji na najechanie myszą na dany element.

Jeślibym sobie coś przypomniał, to dopiszę, ale nie liczyłbym na to. Tak więc niech wątek zostanie bez zaakceptowanej odpowiedzi.

1 użytkowników online, w tym zalogowanych: 0, gości: 1