Suponha que eu tenha um componente:
@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 {
}
Agora, eu gostaria de exibir algum conteúdo padrão se <ng-content>
este componente estiver vazio. Existe uma maneira fácil de fazer isso sem acessar o DOM diretamente?
javascript
angular
Slawomir Dadas
fonte
fonte
Respostas:
Envolva
ng-content
em um elemento HTML como umdiv
para obter uma referência local a ele e vincule angIf
expressão aref.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>`
fonte
ref.children.length
. childNodes conterátext
nós se você formatar seu html com espaços ou novas linhas, mas os filhos ainda estarão vazios.ref.childNodes.length == 0
vez deref.children.length == 0
. Ajudaria bastante se você pudesse editar a resposta para ser consistente. Erro fácil, não bater em você. :)!ref.hasChildNodes()
vez deref.nativeElement.childNodes.length == 0
Faltam algumas respostas de @pixelbits. Precisamos verificar não apenas a
children
propriedade, porque quaisquer quebras de linha ou espaços no modelo pai causarão ochildren
elemento com texto em branco \ quebras de linha. Melhor verificar.innerHTML
e.trim()
isso.Exemplo de trabalho:
<span #ref><ng-content></ng-content></span> <span *ngIf="!ref.innerHTML.trim()"> Content if empty </span>
fonte
element.children.length
ouelement.childnodes.length
, dependendo do que você deseja solicitar.EDITAR 17/03/2020
CSS puro (2 soluções)
Fornece conteúdo padrão se nada for projetado no conteúdo ng.
Seletores possíveis:
:only-child
seletor. Veja esta postagem aqui:: seletor filho únicoEste requer menos código / marcação. Suporte desde o IE 9: Posso usar: filho único
:empty
seletor. Apenas leia mais.Suporte do IE 9 e parcialmente desde 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; }
Caso não esteja funcionando
Esteja ciente de que ter pelo menos um espaço em branco não é considerado vazio. Angular remove os espaços em branco, mas apenas no caso de não ser:
<div class="wrapper"><!-- --><ng-content select="my-component"></ng-content><!-- --></div>
ou
<div class="wrapper"><ng-content select="my-component"></ng-content</div>
fonte
empty
pseudoclasse css<loader [data]="allDataWeNeed"> <desired-component *loadingRender><desired-component> <other-default-component *renderWhenEmptyResult></other-default-component> </loader>
e no componente de carregamento, você poderia mostrar o carregamento de desempenho percebido, enquanto os dados estão carregando. Você pode escrever / resolver de maneiras diferentes. Esta é uma demonstração de como você pode resolver isso.Quando você injeta o conteúdo, adicione uma variável de referência:
e em sua classe de componente obtenha uma referência ao conteúdo injetado com @ContentChild ()
@ContentChild('content') content: ElementRef;
então, em seu modelo de componente, você pode verificar se a variável de conteúdo tem um valor
<div> <ng-content></ng-content> <span *ngIf="!content"> Display this if ng-content is empty! </span> </div>
fonte
<MyContainer></MyContainer>
. Sua solução espera que os usuários para criar uma sub-elemento sob myContainer:<MyContainer><div #content></div></MyContainer>
. Embora essa seja uma possibilidade, eu não diria que é superior.Injete
elementRef: ElementRef
e verifique seelementRef.nativeElement
tem filhos. Isso pode funcionar apenas comencapsulation: ViewEncapsulation.Native
.Enrole a
<ng-content>
tag e verifique se ela tem filhos. Isso não funciona comencapsulation: ViewEncapsulation.Native
.<div #contentWrapper> <ng-content></ng-content> </div>
e verifique se tem algum filho
@ViewChild('contentWrapper') contentWrapper; ngAfterViewInit() { contentWrapper.nativeElement.childNodes... }
(não testado)
fonte
@ViewChild
. Embora "Legal", ViewChild não deve ser usado para acessar nós-filhos dentro de um modelo. Isso é um antipadrão porque, embora os pais possam saber sobre os filhos, eles não devem acasalar-se com eles, pois geralmente leva ao acasalamento patológico ; uma forma mais apropriada de transporte de dados ou tratamento de solicitações é usar metodologias orientadas a eventos .@ViewChild
. Obrigado por adicionar algum equilíbrio aos meus comentários - considero ambos os nossos comentários tão dignos de consideração quanto o outro.@ViewChild()
venha do nome. "Filhos" não são necessariamente filhos, são apenas a parte declarativa do componente (a meu ver). Se as instâncias do componente criadas para esta marcação forem acessos, isso é claro, uma história diferente, porque exigiria conhecimento pelo menos sobre sua interface pública e isso criaria um acoplamento estreito. Esta é uma discussão muito interessante. Preocupa-me não ter tempo suficiente para pensar sobre esses assuntos porque, com essas estruturas, muitas vezes se gasta tempo para descobrir qualquer meio.Se você deseja exibir um conteúdo padrão, por que você não usa apenas o seletor 'filho único' do css.
https://www.w3schools.com/cssref/sel_only-child.asp
por exemplo: HTML
<div> <ng-content></ng-content> <div class="default-content">I am deafult</div> </div>
css
.default-content:not(:only-child) { display: none; }
fonte
Implementei uma solução usando o decorador @ContentChildren , que é semelhante à resposta de @Lerner .
De acordo com a documentação , este decorador:
Portanto, o código necessário no componente pai será:
<app-my-component> <div #myComponentContent> This is my component content </div> </app-my-component>
Na classe do componente:
@ContentChildren('myComponentContent') content: QueryList<ElementRef>;
Então, no modelo de componente:
<div class="container"> <ng-content></ng-content> <span *ngIf="*ngIf="!content.length""><em>Display this if ng-content is empty!</em></span> </div>
Exemplo completo : https://stackblitz.com/edit/angular-jjjdqb
Eu encontrei esta solução implementada em componentes angulares, para
matSuffix
, no componente de campo de formulário .Na situação em que o conteúdo do componente é injetado posteriormente, depois que o aplicativo é inicializado, também podemos usar uma implementação reativa, inscrevendo-se no
changes
evento deQueryList
: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(); } }
Exemplo completo : https://stackblitz.com/edit/angular-essvnq
fonte
Com o Angular 10, ele mudou ligeiramente. Você usaria:
<div #ref><ng-content></ng-content></div> <span *ngIf="ref.children.length == 0"> Display this if ng-content is empty! </span>
fonte
No meu caso, tenho que ocultar o pai do conteúdo-ng vazio:
<span class="ml-1 wrapper"> <ng-content> </ng-content> </span>
O css simples funciona:
.wrapper { display: inline-block; &:empty { display: none; } }
fonte