Supposons que j'ai un composant:
@Component({
selector: 'MyContainer',
template: `
<div class="container">
<!-- some html skipped -->
<ng-content></ng-content>
<span *ngIf="????">Display this if ng-content is empty!</span>
<!-- some html skipped -->
</div>`
})
export class MyContainer {
}
Maintenant, je voudrais afficher du contenu par défaut si <ng-content>
pour ce composant est vide. Existe-t-il un moyen simple de le faire sans accéder directement au DOM?
javascript
angular
Slawomir Dadas
la source
la source
Réponses:
Enveloppez
ng-content
dans un élément HTML comme adiv
pour obtenir une référence locale à celui-ci, puis liez l'ngIf
expression àref.children.length == 0
:template: `<div #ref><ng-content></ng-content></div> <span *ngIf="ref.nativeElement.childNodes.length == 0"> Display this if ng-content is empty! </span>`
la source
ref.children.length
. childNodes contiendra destext
nœuds si vous formatez votre html avec des espaces ou de nouvelles lignes, mais les enfants seront toujours vides.ref.childNodes.length == 0
place deref.children.length == 0
. Cela aiderait beaucoup si vous pouviez modifier la réponse pour qu'elle soit cohérente. Erreur facile, ne pas vous dénigrer. :)!ref.hasChildNodes()
place deref.nativeElement.childNodes.length == 0
Il manque des réponses @pixelbits. Nous devons vérifier non seulement la
children
propriété, car toutchildren
saut de ligne ou espace dans le modèle parent entraînera un élément avec du texte vide \ sauts de ligne. Mieux vaut vérifier.innerHTML
et.trim()
ça.Exemple de travail:
<span #ref><ng-content></ng-content></span> <span *ngIf="!ref.innerHTML.trim()"> Content if empty </span>
la source
element.children.length
ouelement.childnodes.length
, en fonction de ce que vous voulez demander.MODIFIER 17.03.2020
CSS pur (2 solutions)
Fournit du contenu par défaut si rien n'est projeté dans ng-content.
Sélecteurs possibles:
:only-child
sélecteur. Voir cet article ici:: Sélecteur pour enfant uniqueCelui-ci nécessite moins de code / balisage. Prise en charge depuis IE 9: Puis-je utiliser: enfant unique
:empty
sélecteur. Lisez plus loin.Prise en charge d'IE 9 et partiellement depuis IE 7/8: https://caniuse.com/#feat=css-sel3
HTML
<div class="wrapper"> <ng-content select="my-component"></ng-content> </div> <div class="default"> This shows something default. </div>
CSS
.wrapper:not(:empty) + .default { display: none; }
Au cas où ça ne marche pas
Sachez qu'avoir au moins un espace blanc est considéré comme n'étant pas vide. Angular supprime les espaces, mais juste au cas où ce ne serait pas le cas:
<div class="wrapper"><!-- --><ng-content select="my-component"></ng-content><!-- --></div>
ou
<div class="wrapper"><ng-content select="my-component"></ng-content</div>
la source
empty
pseudoclasse css<loader [data]="allDataWeNeed"> <desired-component *loadingRender><desired-component> <other-default-component *renderWhenEmptyResult></other-default-component> </loader>
et dans le composant de chargement, vous pourriez afficher le chargement de performance perçu, tandis que les données sont en cours de chargement. Vous pouvez l'écrire / le résoudre de différentes manières. Ceci est une démonstration de la façon dont vous pourriez le résoudre.Lorsque vous injectez le contenu, ajoutez une variable de référence:
et dans votre classe de composant, obtenez une référence au contenu injecté avec @ContentChild ()
@ContentChild('content') content: ElementRef;
donc dans votre modèle de composant, vous pouvez vérifier si la variable de contenu a une valeur
<div> <ng-content></ng-content> <span *ngIf="!content"> Display this if ng-content is empty! </span> </div>
la source
<MyContainer></MyContainer>
. Votre solution attend aux utilisateurs de créer un sous-élément sous MyContainer:<MyContainer><div #content></div></MyContainer>
. Bien que ce soit une possibilité, je ne dirais pas que c'est supérieur.Injectez
elementRef: ElementRef
et vérifiez sielementRef.nativeElement
a des enfants. Cela pourrait fonctionner uniquement avecencapsulation: ViewEncapsulation.Native
.Enveloppez l'
<ng-content>
étiquette et vérifiez si elle a des enfants. Cela ne fonctionne pas avecencapsulation: ViewEncapsulation.Native
.<div #contentWrapper> <ng-content></ng-content> </div>
et vérifiez s'il a des enfants
@ViewChild('contentWrapper') contentWrapper; ngAfterViewInit() { contentWrapper.nativeElement.childNodes... }
(pas testé)
la source
@ViewChild
. Bien que "Légal", ViewChild ne doit pas être utilisé pour accéder aux nœuds enfants dans un modèle. C'est un anti-modèle parce que, bien que les parents connaissent les enfants, ils ne devraient pas s'accoupler avec eux car cela conduit généralement à un couplage pathologique ; une forme plus appropriée de transport de données ou de traitement des demandes consiste à utiliser des méthodologies basées sur les événements .@ViewChild
. Merci d'avoir ajouté un peu d'équilibre à mes commentaires - je trouve nos deux commentaires tout aussi dignes d'être pris en considération que l'autre.@ViewChild()
vient du nom. Les "enfants" ne sont pas nécessairement des enfants, ils ne sont que la partie déclarative du composant (comme je le vois). Si les instances de composant créées pour ce balisage sont des accès, il s'agit bien sûr d'une histoire différente, car cela nécessiterait des connaissances au moins sur leur interface publique et cela créerait en fait un couplage étroit. C'est une discussion très intéressante. Cela m'inquiète de ne pas avoir assez de temps pour réfléchir à de telles questions, car avec de tels cadres trop souvent, le temps est brûlé pour trouver un moyen.Si vous voulez afficher un contenu par défaut, pourquoi n'utilisez-vous pas simplement le sélecteur 'only-child' de css.
https://www.w3schools.com/cssref/sel_only-child.asp
par exemple: HTML
<div> <ng-content></ng-content> <div class="default-content">I am deafult</div> </div>
css
.default-content:not(:only-child) { display: none; }
la source
Avec Angular 10, cela a légèrement changé. Vous utiliseriez:
<div #ref><ng-content></ng-content></div> <span *ngIf="ref.children.length == 0"> Display this if ng-content is empty! </span>
la source
Dans mon cas, je dois masquer le parent du ng-content vide:
<span class="ml-1 wrapper"> <ng-content> </ng-content> </span>
Le CSS simple fonctionne:
.wrapper { display: inline-block; &:empty { display: none; } }
la source
J'ai implémenté une solution en utilisant @ContentChildren décorateur , qui est en quelque sorte similaire à la réponse de @ Lerner.
Selon la documentation , ce décorateur:
Ainsi, le code nécessaire dans le composant parent sera:
<app-my-component> <div #myComponentContent> This is my component content </div> </app-my-component>
Dans la classe de composants:
@ContentChildren('myComponentContent') content: QueryList<ElementRef>;
Ensuite, dans le modèle de composant:
<div class="container"> <ng-content></ng-content> <span *ngIf="*ngIf="!content.length""><em>Display this if ng-content is empty!</em></span> </div>
Exemple complet : https://stackblitz.com/edit/angular-jjjdqb
J'ai trouvé cette solution implémentée dans des composants angulaires, pour
matSuffix
, dans le composant form-field .Dans la situation où le contenu du composant est injecté ultérieurement, après l'initialisation de l'application, on peut également utiliser une implémentation réactive, en souscrivant à l'
changes
événement duQueryList
:export class MyComponentComponent implements AfterContentInit, OnDestroy { private _subscription: Subscription; public hasContent: boolean; @ContentChildren('myComponentContent') content: QueryList<ElementRef>; constructor() {} ngAfterContentInit(): void { this.hasContent = (this.content.length > 0); this._subscription = this.content.changes.subscribe(() => { // do something when content updates // this.hasContent = (this.content.length > 0); }); } ngOnDestroy() { this._subscription.unsubscribe(); } }
Exemple complet : https://stackblitz.com/edit/angular-essvnq
la source