html - Bruke *ngFor i CSS Grid Layout viser uønsket alt i én kolonne
Jeg er ny innen programmering og webutvikling generelt. Jeg er i ferd med å lage en personlig nettside.
Jeg vil plassere bokser i et rutenett med 4 kolonner, likt det du ser her: https://devpost.com/software/search?query=is%3Afeatured
Hver av disse boksene representerer et objekt, og jeg vil kunne vise noe av dataene i boksen, og resten av dataene i en popup-dialog når du klikker på boksen.
Jeg har lekt litt med CSS-gridoppsettet, som blir populært for tiden (anbefaler sterkt denne videoen: https://www.youtube.com/watch?v=7kVeCqQCxlk).
Greia med 4 kolonner fungerer når jeg hardkoder en haug med div-elementer inne i en wrapper-div. Men hver gang jeg bruker *ngFor på wrapperen som inneholder arrayen min med data og sender inn dataene fra hver iterasjon til et indre div-element, blir rutenett-oppsettet ødelagt, og alt plasseres i en kolonne.
Når jeg manuelt legger inn dataene ved å bruke flere div-elementer (item2 her), fungerer det som ønsket:
.wrapper {
margin-left: 1em;
margin-right: 1em;
display: grid;
grid-template-rows: auto;
grid-template-columns: repeat(4, 1fr);
grid-row-gap: 1em;
grid-column-gap: 1em;
}<div class="wrapper">
<div class="item2" style="background-color: deepskyblue;">
<img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
<p>more text here.</p>
</div>
<div class="item2" style="background-color: deepskyblue;">
<img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
<p>more text here.</p>
</div>
<div class="item2" style="background-color: deepskyblue;">
<img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
<p>more text here.</p>
</div>
<div class="item2" style="background-color: deepskyblue;">
<img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
<p>more text here.</p>
</div>
<div class="item2" style="background-color: deepskyblue;">
<img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
<p>more text here.</p>
</div>
</div>Ved bruk av *ngFor... kjører det for lengden på arrayen "stickyNotes," men stabler boksene bare under hver rad.
<div class="wrapper" *ngFor="let s of stickyNotes; let i = index" >
<div class="item2" style="background-color: deepskyblue;">
<img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
<p>more text here.</p>
<p>{{s.title}}</p>
</div>
</div>Min løsning på dette var... å ha dette div-elementet 4 ganger med i som øker med 1 på *ngIf (i+1, i+2, osv.). Problemet her er at når en ny rad starter, blir grid-row-gap i CSS ignorert.
<div class="item2" style="background-color: deepskyblue;" *ngIf="i < stickyNotes.length && i%4 === 0">
<img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
<p>more text here.</p>
<p>{{stickyNotes[i].title}}</p>
</div>
<div class="item2" style="background-color: deepskyblue;" *ngIf="i+1 < stickyNotes.length && i%4 === 0">
<img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
<p>more text here.</p>
<p>{{stickyNotes[i+1].title}}</p>
</div>
<!--2 more times until i+3-->Jeg lurer på om det finnes en måte å lage en tilpasset iterabel direktiv på uten å ødelegge grid-egenskapen og uten å ha item2-klassen kodet 4 ganger (eller noen andre metoder).
Jeg har prøvd bootstrap rad- og kolonneattributter, men med 4 kolonner var ikke responsiviteten like bra som med rutenettoppsettet.
All hjelp eller forslag vil bli satt pris på!
Svar #1
*ngFor gjentar elementet du legger det til. Sett det enkelt på div.item2, så burde det fungere:
<div class="wrapper" >
<div class="item2" *ngFor="let s of stickyNotes; let i = index" style="background-color: deepskyblue;" >
<img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
<p>more text here.</p>
<p>{{s.title}}</p>
</div>
</div>
Svaret som ble gitt av Vega vil også fungere, men <ng-container> er ikke nødvendig (så lenge du ikke legger en annen strukturell direktiv på div.item2-elementet), fordi stjernen bare er syntaktisk sukker og utvider seg til noe lignende:
<div class="wrapper" >
<ng-template ngFor let-s [ngForOf]="stickyNotes" let-i="index">
<div class="item2" style="background-color: deepskyblue;">
<img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
<p>more text here.</p>
<p>{{s.title}}</p>
</div>
</ng-template>
</div>
Grunnen til begrensningen på én strukturdirektiv per element er gitt her:
En dag vil du ønske å gjenta en blokk med HTML, men bare når en bestemt betingelse er sann. Du vil prøve å sette både en *ngFor og en *ngIf på det samme vertselementet. Angular vil ikke tillate det. Du kan bare bruke én strukturell direktiv på et element.
Årsaken er enkelhet. Strukturelle direktiver kan gjøre komplekse ting med host-elementet og dets etterkommere. Når to direktiver gjør krav på det samme host-elementet, hvilket får da forrang? Hvilket bør gå først, NgIf eller NgFor? Kan NgIf kansellere effekten av NgFor? Hvis ja (og det ser ut til at det bør være slik), hvordan bør Angular generalisere evnen til å kansellere for andre strukturelle direktiver?
Det finnes ingen enkle svar på disse spørsmålene. Å forby flere strukturelle direktiver gjør dem meningsløse. Det finnes en enkel løsning for dette brukstilfellet: sett *ngIf på et containerelement som omslutter *ngFor-elementet. Ett eller begge elementene kan være en ng-container, så du ikke trenger å introdusere ekstra HTML-nivåer.
Svar #2
Prøv denne syntaksen:
<div class="wrapper">
<ng-container *ngFor="let s of stickyNotes; let i = index">
<div class="item2" style="background-color: deepskyblue;">
<img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test">
<p>more text here.</p>
<p>{{s.title}}</p>
</div>
</ng-container>
</div>
