Mam problem z próbą użycia Angulara *ngFor
i *ngIf
tego samego elementu.
Podczas próby przechodzenia przez kolekcję w *ngFor
kolekcji kolekcja jest postrzegana jako null
konsekwentnie nieudana podczas próby uzyskania dostępu do jej właściwości w szablonie.
@Component({
selector: 'shell',
template: `
<h3>Shell</h3><button (click)="toggle()">Toggle!</button>
<div *ngIf="show" *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
`
})
export class ShellComponent implements OnInit {
public stuff:any[] = [];
public show:boolean = false;
constructor() {}
ngOnInit() {
this.stuff = [
{ name: 'abc', id: 1 },
{ name: 'huo', id: 2 },
{ name: 'bar', id: 3 },
{ name: 'foo', id: 4 },
{ name: 'thing', id: 5 },
{ name: 'other', id: 6 },
]
}
toggle() {
this.show = !this.show;
}
log(thing) {
console.log(thing);
}
}
Wiem, że łatwym rozwiązaniem jest przejście *ngIf
o jeden poziom wyżej, ale w scenariuszach takich jak zapętlanie elementów listy w a ul
skończy się albo pustym, li
jeśli kolekcja jest pusta, albo li
opakowaniem w zbędne elementy kontenera.
Przykład na tym plnkr .
Zwróć uwagę na błąd konsoli:
EXCEPTION: TypeError: Cannot read property 'name' of null in [{{thing.name}} in ShellComponent@5:12]
Czy robię coś źle, czy to błąd?
angular
ngfor
angular-ng-if
garethdn
źródło
źródło
Odpowiedzi:
Angular v2 nie obsługuje więcej niż jednej dyrektywy strukturalnej dla tego samego elementu.
Aby obejść ten
<ng-container>
problem, należy użyć elementu, który pozwala na użycie osobnych elementów dla każdej dyrektywy strukturalnej, ale nie jest on stemplowany na DOM .<ng-template>
(<template>
przed Angular v4) pozwala robić to samo, ale z inną składnią, która jest myląca i nie jest już zalecanaźródło
ngFor
na<ng-container>
elemencie ingIf
na<div>
. Możesz także mieć dwa zagnieżdżone<ng-container>
zawijanie pliku<div>
.<ng-container>
jest tylko elementem pomocniczym, który nie zostanie dodany do DOM.<ng-container>
. Zachowuje się tak samo,<template>
ale pozwala na stosowanie „normalnej” składni dla dyrektyw strukturalnych.Jak wszyscy zauważyli, mimo że posiadanie wielu dyrektyw szablonów w jednym elemencie działa w wersji kątowej 1.x, nie jest to dozwolone w wersji kątowej 2. Więcej informacji można znaleźć tutaj: https://github.com/angular/angular/issues/ 7315
2016 kątowa 2 beta
rozwiązaniem jest użycie
<template>
symbolu zastępczego, więc kod wygląda takale z jakiegoś powodu powyższe nie działa
2.0.0-rc.4
w takim przypadku możesz użyć tegoZaktualizowana odpowiedź 2018
Dzięki aktualizacjom, teraz w 2018 r. Zaleca się stosowanie
<ng-container>
zamiast wersji kątowej v6<template>
oto zaktualizowana odpowiedź.
źródło
Jak wspomniano @Zyzle i @ Günter wspomniane w komentarzu ( https://github.com/angular/angular/issues/7315 ), nie jest to obsługiwane.
Z
<li>
gdy lista jest pusta, nie ma pustych elementów. Nawet<ul>
element nie istnieje (zgodnie z oczekiwaniami).Gdy lista jest zapełniona, nie ma zbędnych elementów kontenera.
Dyskusja github (4792) , które @Zyzle wspomniano w swoim komentarzu przedstawiono również inne rozwiązanie używając
<template>
(poniżej używam oryginalnego znaczników - używając<div>
s):To rozwiązanie nie wprowadza również żadnych dodatkowych / zbędnych elementów kontenera.
źródło
<template>
to sposób na dodanie elementu nadrzędnego, który nie pojawi się w danych wyjściowych.w html:
w css:
źródło
Nie można mieć
ngFor
ingIf
na tym samym elemencie. Co możesz zrobić, to wstrzymać się z zapełnianiem tablicy, w której używasz,ngFor
dopóki nie klikniesz przełącznika w twoim przykładzie.Oto podstawowy (niezbyt świetny) sposób: http://plnkr.co/edit/Pylx5HSWIZ7ahoC7wT6P
źródło
you can't
nie jest to naprawdę dobra odpowiedź, prawda?Nie możesz użyć więcej niż jednego
Structural Directive
w Angular na tym samym elemencie, robi to nieporozumienia i strukturę, więc musisz zastosować je w 2 osobnych zagnieżdżonych elementach (lub możesz użyćng-container
), przeczytaj to zdanie od zespołu Angular:Możesz więc użyć
ng-container
(Angular4) jako opakowania (zostanie usunięte z dom) lub div lub span, jeśli masz klasę lub niektóre inne atrybuty, jak poniżej:źródło
To zadziała, ale element nadal będzie w DOM.
źródło
Poniższa tabela zawiera tylko pozycje z ustawioną wartością „dla początkujących”. Wymaga zarówno
*ngFor
i,*ngIf
aby zapobiec niechcianym wierszom w html.Pierwotnie miał
*ngIf
i*ngFor
na tym samym<tr>
tagu, ale nie działa. Dodano<div>
do*ngFor
pętli i umieszczone*ngIf
w<tr>
tagu, działa zgodnie z oczekiwaniami.źródło
<div>
wnętrze stołu było pomysłem goosowym, zwłaszcza gdy istnieją lepsze alternatywy. Czy sprawdziłeś, czy tak działa w IE, co jest szczególnie wybredne w przypadku elementów w<table>
Zaktualizowano do angular2 beta 8
Od wersji angular2 beta 8 możemy teraz używać
*ngIf
i*ngFor
na tym samym komponencie patrz tutaj .Alternatywny:
Czasami nie możemy używać tagów HTML wewnątrz innych, takich jak in
tr
,th
(table
) lub inli
(ul
). Nie możemy użyć innego tagu HTML, ale musimy wykonać pewne czynności w tej samej sytuacji, abyśmy mogli tag funkcji HTML5<template>
w ten sposób .ng Do korzystania z szablonu:
ng Jeśli używasz szablonu:
Aby uzyskać więcej informacji na temat dyrektyw strukturalnych w angular2, zobacz tutaj .
źródło
źródło
Możesz także użyć
ng-template
(zamiast szablonu. Zobacz uwaga dotycząca używania znacznika szablonu) do zastosowania zarówno * ngFor, jak i ngIf na tym samym elemencie HTML. Oto przykład, w którym możesz użyć zarówno * ngIf, jak i * ngFor dla tego samego elementu tr w tabeli kątowej.gdzie
fruiArray = ['apple', 'banana', 'mango', 'pineapple']
.Uwaga:
Jedynym zastrzeżeniem używania
template
tagu zamiastng-template
tagu jest to, że rzucaStaticInjectionError
w niektórych miejscach.źródło
źródło
Nie można użyć wielu dyrektyw strukturalnych dla tego samego elementu. Zawiń swój element
ng-template
i użyj tam jednej dyrektywy strukturalnejźródło
Możesz to zrobić w inny sposób, sprawdzając długość tablicy
źródło
app.component.ts
app.component.html
Wynik
źródło