Un caso muy común para hacer un ejemplo de componentes anidados y usando ng-content, son los Cards, tal cual lo hace Angular Material, en este caso se nos presenta un diseño similar al siguiente
Una buena practica que debemos tener como desarrolladores y que a mi me funciona es definir la arquitectura antes de "echar" codigo.
Luego de analizar el diseño anterior, nos encontramos que tenemos un Home, con dos Cards, que si uno quisiera podrían ser dos componentes separados compartiendo estilos, pero al final se puede cruzar la línea delgada de reescribir código.
En este caso crearemos un componente Card, que sera nuestro Layout del card, un componente CardHeader, y un componente CardBody, ya que vemos que si tiene Header es el mismo comportamiento, y con nuestro amigo "ng-content" recibiremos los componentes o data que le pasemos al Card.
Para este ejercicio vamos a representar visualmente las cosas, no va a ser necesario comportamientos del form o de las urls de los posts, eso es solo demostrativo
Iniciamos el proyecto
ng new MyNestedComponents
Y para darle un poco de estilo como del diseño, nuestro style.css el app.component.css quedan de la siguiente manera
/* You can add global styles to this file, and also import other style files */
body {
margin: 0;
font-family: system-ui;
}
Ahora creamos los componentes a utilizar:
ng g c components/card
ng g c components/card-header
ng g c components/card-body
ng g c components/contact-form
ng g c components/item-post
Nuestro app.module.ts debe quedar de la siguiente manera:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { CardComponent } from './components/card/card.component';
import { CardHeaderComponent } from './components/card-header/card-header.component';
import { ContactFormComponent } from './components/contact-form/contact-form.component';
import { ItemPostComponent } from './components/item-post/item-post.component';
import { CardBodyComponent } from './components/card-body/card-body.component';
@NgModule({
declarations: [
AppComponent,
CardComponent,
CardHeaderComponent,
ContactFormComponent,
ItemPostComponent,
CardBodyComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Empezamos a crear nuestros componentes
Agregamos los estilos correspondientes a cada Layout y creamos el html
card.component.css
.card {
background-color: white;
box-shadow: 0 2px 1px -1px rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14),
0 1px 3px 0 rgba(0, 0, 0, 0.12);
}
.card-component.html
<div class="card">
<ng-content></ng-content>
</div>
.card-component.css
.header {
border-bottom: 1px solid #d0d0d0;
padding: 14px;
font-size: 1rem;
font-weight: 700;
}
.card-header.component.html
<div class="header">
<ng-content></ng-content>
</div>
.card-body.component.css
.card-body {
padding: 1rem;
}
.card-body.component.html
<div class="card-body">
<ng-content></ng-content>
</div>
Antes de escribir el primer card, modifiquemos el componente item-post
.item-post.component.ts
import { Component, Input, OnInit } from '@angular/core';
@Component({
selector: 'app-item-post',
templateUrl: './item-post.component.html',
styleUrls: ['./item-post.component.css'],
})
export class ItemPostComponent implements OnInit {
@Input() value: string;
constructor() {}
ngOnInit(): void {}
}
.item-post.component.css
.item-post {
border: 1px solid gray;
padding: 0.5rem;
font-size: 1rem;
font-weight: 700;
margin-bottom: 1rem;
}
.item-post.component.html
<div class="item-post">
{{ value }}
</div>
En el app.component.ts listamos los "posts"
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
title = 'AngularNestedComponents';
posts: string[] = ['Primer post', 'Segundo Post', 'Tercer post'];
}
Y nuestro primer Card quedaría de la siguiente manera:
<app-card>
<app-card-header> Mis Posts </app-card-header>
<app-card-body>
<ng-container *ngFor="let item of posts">
<app-item-post [value]="item"></app-item-post>
</ng-container>
</app-card-body>
</app-card>
Ahora maquetamos nuestro contact-form
.contact-form.component.html
<div class="content-form">
<div class="form-group">
<label>Nombre</label>
<input type="text" class="form-control" />
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" />
</div>
<div class="form-group">
<label>Mensaje</label>
<textarea name="" id="" cols="30" rows="10"></textarea>
</div>
<div class="cta">
<button>Enviar</button>
</div>
</div>
.content-form {
padding: 14px;
margin: 0 auto;
max-width: 440px;
width: 90%;
}
.content-form .form-group {
margin-bottom: 10px;
}
.content-form .form-group label {
font-weight: 700;
display: block;
}
.content-form .form-group input {
padding: 6px;
border: 1px solid #b7b7b7;
border-radius: 4px;
margin-top: 7px;
width: 100%;
}
.content-form .form-group textarea {
padding: 6px;
border: 1px solid #b7b7b7;
border-radius: 4px;
margin-top: 7px;
width: 100%;
}
button {
background-color: #00d5ff;
border: 0;
padding: 10px;
border-radius: 5px;
width: 170px;
}
Y nuestro app.component.html
<main>
<div class="container">
<h1>HenryGBCDev</h1>
<app-card>
<app-card-header> Mis Posts </app-card-header>
<app-card-body>
<ng-container *ngFor="let item of posts">
<app-item-post [value]="item"></app-item-post>
</ng-container>
</app-card-body>
</app-card>
<app-card>
<app-card-header> Contactanme </app-card-header>
<app-card-body>
<app-contact-form></app-contact-form>
</app-card-body>
</app-card>
</div>
</main>
Podemos ver los beneficios del ng-content
y que también nos ayuda a leer mucho mejor el código, entre mas componetizado este nuestra aplicación, aparte de que se ve mucho mejor, nos ayuda con el mantenimiento a los desarrolladores.
https://github.com/HenryGBC/AngularNestedComponents
Sígueme en mis redes, donde sigo compartiendo contenido de código y sobre todo de Frontend.
Top comments (0)