Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 40 additions & 4 deletions docs/develop/basic/angular17.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,22 @@ Si abrimos el proyecto con el IDE que tengamos (Visual Studio Code en el caso de
* `app.html` → contiene la plantilla inicial del proyecto escrita en HTML.
* `app.scss` → contiene los estilos CSS privados de la plantilla inicial.

Vamos a modificar este código inicial para ver como funciona. Abrimos el fichero `app.component.ts` y modificamos la línea donde se asigna un valor a la variable `title`.
!!! info
Comprueba el fichero `tsconfig.json` del proyecto, puede que estés usando el modo `strict` o tengas `strictNullChecks` a true.
Con estas propiedades activadas se obliga al compilador a tratar los tipos `null` y `undefined` de manera más estricta.

**Comportamiento sin strictNullChecks (false):**
- `null` y `undefined` se consideran valores válidos para cualquier tipo
- Puedes asignar `null` o `undefined` a variables de cualquier tipo sin errores
- Mayor flexibilidad pero menos seguridad de tipos

**Comportamiento con strictNullChecks (true):**
- Solo los tipos `null` y `undefined` pueden contener esos valores explícitamente
- Debes usar tipos union para permitir nulidad: `string | null`, `number | undefined`
- El compilador previene acceso a propiedades/métodos en valores potencialmente nulos
- Mayor seguridad de tipos y detección de errores en tiempo de compilación

Vamos a modificar el código inicial para ver como funciona. Abrimos el fichero `app.component.ts` y modificamos la línea donde se asigna un valor a la variable `title`.

=== "app.component.ts"
``` TypeScript
Expand Down Expand Up @@ -265,7 +280,7 @@ Ahora vamos a construir la pantalla. Para manejar la información del listado, n

=== "category.ts"
``` Typescript
export class Category {
export interface Category {
id: number;
name: string;
}
Expand Down Expand Up @@ -685,7 +700,14 @@ Ahora vamos a darle forma al formulario de editar y crear. Para ello vamos al ht
}

onSave() {
const category: Category = { id: this.id(), name: this.name() };
const id = this.id();
const name = this.name();

if(!name) {
return;
}

const category = { id, name } as Category;
this.categoryService.saveCategory(category).subscribe(() => {
this.dialogRef.close(true);
});
Expand All @@ -700,6 +722,13 @@ Ahora vamos a darle forma al formulario de editar y crear. Para ello vamos al ht

Si te fijas en el código TypeScript, hemos añadido en el método `onSave` una llamada al servicio de `CategoryService` que aunque no realice ninguna operación de momento, por lo menos lo dejamos preparado para conectar con el servidor.

!!! Cast de tipo para resolver incompatibilidad de tipos
Se utiliza "as Category" porque el tipo obtenido del servidor siempre llegará con id,
sin embargo al crear una nueva categoría no dispondremos de valor hasta que lo genere el backend

⚠️ Nota: Usar con cuidado, ya que bypasea la validación de tipos.
Considera validar los datos en tiempo de ejecución si es crítico (cómo se hace con la propiedad `name`)

Además, como siempre, al utilizar componentes `matInput`, `matForm`, `matError` hay que añadir los módulos correspondientes como dependencias en el atributo imports.

Ahora podemos navegar y abrir el cuadro de diálogo mediante el botón `Nueva categoría` para ver como queda nuestro formulario.
Expand Down Expand Up @@ -839,7 +868,14 @@ Y los Dialog:
}

onSave() {
const category: Category = { id: this.id(), name: this.name() };
const id = this.id();
const name = this.name();

if(!name) {
Comment thread
jsegarr marked this conversation as resolved.
return;
}

const category = { id, name } as Category;
this.categoryService.saveCategory(category).subscribe(() => {
this.dialogRef.close(true);
});
Expand Down
31 changes: 22 additions & 9 deletions docs/develop/filtered/angular17.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Lo primero que vamos a hacer es crear el modelo en `game/model/Game.ts` con toda
import { Author } from "../../author/model/Author";
import { Category } from "../../category/model/Category";

export class Game {
export interface Game {
id: number;
title: string;
age: number;
Expand Down Expand Up @@ -588,6 +588,7 @@ Ahora sí que tenemos todo listo para implementar el cuadro de diálogo para dar
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select';
import { validateFields } from '../../core/helpers/validation.helper';

@Component({
selector: 'app-game-edit',
Expand Down Expand Up @@ -632,13 +633,26 @@ Ahora sí que tenemos todo listo para implementar el cuadro de diálogo para dar
}

onSave() {
const game: Game = {
id: this.id(),
title: this.title(),
age: this.age(),
category: this.categories().find(c => c.id === this.categoryId()) ?? null,
author: this.authors().find(a => a.id === this.authorId()) ?? null,
};
const id = this.id();
const title = this.title();
const age = this.age();
const categoryId = this.categoryId();
const authorId = this.authorId();

const requiredFields = ["title", "age", "categoryId", "authorId"] as const
const data = { title, age, categoryId, authorId }

if (!validateFields(data, requiredFields)) {
return;
}

const game = {
id,
title,
age,
category: this.categories().find(c => c.id === categoryId) ?? null,
author: this.authors().find(a => a.id === authorId) ?? null,
} as Game;
this.gameService.saveGame(game).subscribe(() => {
this.dialogRef.close(true);
});
Expand All @@ -648,7 +662,6 @@ Ahora sí que tenemos todo listo para implementar el cuadro de diálogo para dar
this.dialogRef.close();
}
}
```

Como puedes ver, para rellenar los componentes seleccionables de dropdown, hemos realizado una consulta al servicio para recuperar todos los autores y categorías, y en la respuesta de cada uno de ellos, hemos buscado en los resultados cuál es el que coincide con el ID enviado desde el listado, y ese es el que hemos fijado en el objeto `Game`.

Expand Down
30 changes: 25 additions & 5 deletions docs/develop/paginated/angular17.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Creamos el modelo en `author/model/Author.ts` con las propiedades necesarias par

=== "Author.ts"
``` TypeScript
export class Author {
export interface Author {
id: number;
name: string;
nationality: string;
Expand Down Expand Up @@ -85,7 +85,7 @@ Así que necesitamos poder enviar y recuperar esa información desde Angular, no

=== "SortPage.ts"
``` TypeScript
export class SortPage {
export interface SortPage {
property: string;
direction: string;
}
Expand All @@ -94,7 +94,7 @@ Así que necesitamos poder enviar y recuperar esa información desde Angular, no
``` TypeScript
import { SortPage } from './SortPage';

export class Pageable {
export interface Pageable {
pageNumber: number;
pageSize: number;
sort: SortPage[];
Expand All @@ -104,7 +104,7 @@ Así que necesitamos poder enviar y recuperar esa información desde Angular, no
``` TypeScript
import { Pageable } from "src/app/core/model/page/Pageable";

export class PaginatedData <TData>{
export interface PaginatedData <TData>{
content: TData[];
pageable: Pageable;
totalElements: number;
Expand Down Expand Up @@ -441,6 +441,7 @@ El último paso es definir la pantalla de diálogo que realizará el alta y modi
import { MatButtonModule } from '@angular/material/button';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { validateFields } from '../../core/helpers/validation.helper';

@Component({
selector: 'app-author-edit',
Expand Down Expand Up @@ -469,7 +470,23 @@ El último paso es definir la pantalla de diálogo que realizará el alta y modi
}

onSave() {
this.authorService.saveAuthor(this.author).subscribe(() => {
const id = this.id();
const name = this.name();
const nationality = this.nationality();

const requiredFields = ["name", "nationality"] as const
const data = { name, nationality }

if (!validateFields(data, requiredFields)) {
return;
}

const author = {
id,
name,
nationality,
} as Author;
this.authorService.saveAuthor(author).subscribe(() => {
this.dialogRef.close(true);
});
}
Expand All @@ -480,6 +497,9 @@ El último paso es definir la pantalla de diálogo que realizará el alta y modi
}
```

!!! info
Podemos usar el helper `validateFields` cuando haya varios campos para validar que sean requeridos

Que debería quedar algo así:

![step4-angular2](../../assets/images/step4-angular2.png)
Expand Down
9 changes: 8 additions & 1 deletion docs/install/angular.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,21 @@ Con esto, scoop ya nos instalará todo lo necesario.

### Angular CLI

El siguiente pasó será instalar una capa de gestión por encima de Nodejs que nos ayudará en concreto con la funcionalidad de Angular. Si no indicamos nada se instalará la última versión del CLI, pero si queremos podemos elegir una versión en concreto añadiendo '@' y el número de la versión correspondiente. Para poder instalarlo, tan solo hay que abrir una consola de msdos y ejecutar el comando y Nodejs ya hará el resto:
El siguiente pasó será instalar una capa de gestión por encima de Nodejs que nos ayudará en concreto con la funcionalidad de Angular. Para poder instalarlo, tan solo hay que abrir una consola de msdos y ejecutar el comando y Nodejs ya hará el resto:

```
npm install -g @angular/cli
```

Si en el comando no indicamos la versión se instalará la última del CLI, pero si queremos podemos elegir una versión en concreto añadiendo '@' y el número de la versión correspondiente.
```
npm install -g @angular/cli@16
```

!!! MUY IMPORTANTE
Si vas a realizar el tutorial de `Angular 17+` deberás instalar la última versión, en el caso de que por alguna razón optes por el tutorial `Angular` deberás instalar la versión 16.


Y con esto ya tendremos todo instalado, listo para empezar a crear los proyectos.

!!! note "Aviso para navegantes corporativos"
Expand Down
Loading
Loading