From d49cbc0de852c9bd9daccb19ed990a5847ffe27e Mon Sep 17 00:00:00 2001
From: Laforge Thomas <30832608+tomalaforge@users.noreply.github.com>
Date: Mon, 17 Jun 2024 20:51:27 +0200
Subject: [PATCH] feat: challenge 54 pipe obs signal (#903)
---
README.md | 2 +-
.../.eslintrc.json | 19 +++++
.../54-pipe-observable-to-signal/README.md | 13 ++++
.../54-pipe-observable-to-signal/project.json | 72 ++++++++++++++++++
.../src/app/app.component.ts | 31 ++++++++
.../src/app/currency.pipe.ts | 15 ++++
.../src/app/currency.service.ts | 30 ++++++++
.../src/app/product-row.component.ts | 34 +++++++++
.../src/app/product.model.ts | 55 +++++++++++++
.../src/assets/.gitkeep | 0
.../src/favicon.ico | Bin 0 -> 15086 bytes
.../src/index.html | 13 ++++
.../54-pipe-observable-to-signal/src/main.ts | 4 +
.../src/styles.scss | 26 +++++++
.../tailwind.config.js | 14 ++++
.../tsconfig.app.json | 10 +++
.../tsconfig.editor.json | 6 ++
.../tsconfig.json | 30 ++++++++
challenge-number.json | 4 +-
.../signal/53-big-signal-performance.md | 1 -
.../signal/54-pipe-observable-to-signal.md | 22 ++++++
docs/src/content/docs/es/index.mdx | 6 +-
docs/src/content/docs/fr/index.mdx | 6 +-
docs/src/content/docs/pt/index.mdx | 6 +-
docs/src/content/docs/ru/index.mdx | 6 +-
libs/shared/ui/src/lib/table.component.ts | 17 ++---
26 files changed, 417 insertions(+), 25 deletions(-)
create mode 100644 apps/signal/54-pipe-observable-to-signal/.eslintrc.json
create mode 100644 apps/signal/54-pipe-observable-to-signal/README.md
create mode 100644 apps/signal/54-pipe-observable-to-signal/project.json
create mode 100644 apps/signal/54-pipe-observable-to-signal/src/app/app.component.ts
create mode 100644 apps/signal/54-pipe-observable-to-signal/src/app/currency.pipe.ts
create mode 100644 apps/signal/54-pipe-observable-to-signal/src/app/currency.service.ts
create mode 100644 apps/signal/54-pipe-observable-to-signal/src/app/product-row.component.ts
create mode 100644 apps/signal/54-pipe-observable-to-signal/src/app/product.model.ts
create mode 100644 apps/signal/54-pipe-observable-to-signal/src/assets/.gitkeep
create mode 100644 apps/signal/54-pipe-observable-to-signal/src/favicon.ico
create mode 100644 apps/signal/54-pipe-observable-to-signal/src/index.html
create mode 100644 apps/signal/54-pipe-observable-to-signal/src/main.ts
create mode 100644 apps/signal/54-pipe-observable-to-signal/src/styles.scss
create mode 100644 apps/signal/54-pipe-observable-to-signal/tailwind.config.js
create mode 100644 apps/signal/54-pipe-observable-to-signal/tsconfig.app.json
create mode 100644 apps/signal/54-pipe-observable-to-signal/tsconfig.editor.json
create mode 100644 apps/signal/54-pipe-observable-to-signal/tsconfig.json
create mode 100644 docs/src/content/docs/challenges/signal/54-pipe-observable-to-signal.md
diff --git a/README.md b/README.md
index 04f9e03..d215b17 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ If you would like to propose a challenge, this project is open source, so feel f
## Challenges
-Check [all 53 challenges](https://angular-challenges.vercel.app/)
+Check [all 54 challenges](https://angular-challenges.vercel.app/)
## Contributors ✨
diff --git a/apps/signal/54-pipe-observable-to-signal/.eslintrc.json b/apps/signal/54-pipe-observable-to-signal/.eslintrc.json
new file mode 100644
index 0000000..d3cd799
--- /dev/null
+++ b/apps/signal/54-pipe-observable-to-signal/.eslintrc.json
@@ -0,0 +1,19 @@
+{
+ "extends": ["../../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts"],
+ "extends": [
+ "plugin:@nx/angular",
+ "plugin:@angular-eslint/template/process-inline-templates"
+ ],
+ "rules": {}
+ },
+ {
+ "files": ["*.html"],
+ "extends": ["plugin:@nx/angular-template"],
+ "rules": {}
+ }
+ ]
+}
diff --git a/apps/signal/54-pipe-observable-to-signal/README.md b/apps/signal/54-pipe-observable-to-signal/README.md
new file mode 100644
index 0000000..495cd3a
--- /dev/null
+++ b/apps/signal/54-pipe-observable-to-signal/README.md
@@ -0,0 +1,13 @@
+# Pipe Observable to Signal
+
+> author: thomas-laforge
+
+### Run Application
+
+```bash
+npx nx serve signal-pipe-observable-to-signal
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/signal/54-pipe-observable-to-signal/).
diff --git a/apps/signal/54-pipe-observable-to-signal/project.json b/apps/signal/54-pipe-observable-to-signal/project.json
new file mode 100644
index 0000000..58d4032
--- /dev/null
+++ b/apps/signal/54-pipe-observable-to-signal/project.json
@@ -0,0 +1,72 @@
+{
+ "name": "signal-pipe-observable-to-signal",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/signal/54-pipe-observable-to-signal/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:application",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/signal/54-pipe-observable-to-signal",
+ "index": "apps/signal/54-pipe-observable-to-signal/src/index.html",
+ "browser": "apps/signal/54-pipe-observable-to-signal/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/signal/54-pipe-observable-to-signal/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ "apps/signal/54-pipe-observable-to-signal/src/favicon.ico",
+ "apps/signal/54-pipe-observable-to-signal/src/assets"
+ ],
+ "styles": ["apps/signal/54-pipe-observable-to-signal/src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "signal-pipe-observable-to-signal:build:production"
+ },
+ "development": {
+ "buildTarget": "signal-pipe-observable-to-signal:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "signal-pipe-observable-to-signal:build"
+ }
+ },
+ "lint": {
+ "executor": "@nx/eslint:lint"
+ }
+ }
+}
diff --git a/apps/signal/54-pipe-observable-to-signal/src/app/app.component.ts b/apps/signal/54-pipe-observable-to-signal/src/app/app.component.ts
new file mode 100644
index 0000000..043310c
--- /dev/null
+++ b/apps/signal/54-pipe-observable-to-signal/src/app/app.component.ts
@@ -0,0 +1,31 @@
+import { TableComponent } from '@angular-challenges/shared/ui';
+import { AsyncPipe } from '@angular/common';
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { CurrencyPipe } from './currency.pipe';
+import { ProductRowComponent } from './product-row.component';
+import { products } from './product.model';
+
+@Component({
+ standalone: true,
+ imports: [AsyncPipe, CurrencyPipe, TableComponent, ProductRowComponent],
+ selector: 'app-root',
+ template: `
+
+
+
+ @for (col of displayedColumns; track col) {
+ | {{ col }} |
+ }
+
+
+
+
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class AppComponent {
+ products = products;
+ displayedColumns = ['name', 'priceA', 'priceB', 'priceC'];
+}
diff --git a/apps/signal/54-pipe-observable-to-signal/src/app/currency.pipe.ts b/apps/signal/54-pipe-observable-to-signal/src/app/currency.pipe.ts
new file mode 100644
index 0000000..e3cc993
--- /dev/null
+++ b/apps/signal/54-pipe-observable-to-signal/src/app/currency.pipe.ts
@@ -0,0 +1,15 @@
+import { inject, Pipe, PipeTransform } from '@angular/core';
+import { map, Observable } from 'rxjs';
+import { CurrencyService } from './currency.service';
+
+@Pipe({
+ name: 'currency',
+ standalone: true,
+})
+export class CurrencyPipe implements PipeTransform {
+ currencyService = inject(CurrencyService);
+
+ transform(price: number): Observable {
+ return this.currencyService.symbol$.pipe(map((s) => `${price}${s}`));
+ }
+}
diff --git a/apps/signal/54-pipe-observable-to-signal/src/app/currency.service.ts b/apps/signal/54-pipe-observable-to-signal/src/app/currency.service.ts
new file mode 100644
index 0000000..5853cea
--- /dev/null
+++ b/apps/signal/54-pipe-observable-to-signal/src/app/currency.service.ts
@@ -0,0 +1,30 @@
+import { Injectable } from '@angular/core';
+import { BehaviorSubject, map } from 'rxjs';
+
+export interface Currency {
+ name: string;
+ code: string;
+ symbol: string;
+}
+
+export const currency: Currency[] = [
+ { name: 'Euro', code: 'EUR', symbol: '€' },
+ { name: 'Dollar US', code: 'USD', symbol: 'US$' },
+ { name: 'Dollar Autralien', code: 'AUD', symbol: 'AU$' },
+ { name: 'Livre Sterling', code: 'GBP', symbol: '£' },
+ { name: 'Dollar Canadien', code: 'CAD', symbol: 'CAD' },
+];
+
+@Injectable()
+export class CurrencyService {
+ private code = new BehaviorSubject('EUR');
+
+ readonly code$ = this.code.asObservable();
+ readonly symbol$ = this.code$.pipe(
+ map((code) => currency.find((c) => c.code === code)?.symbol ?? code),
+ );
+
+ public updateCode(code: string) {
+ this.code.next(code);
+ }
+}
diff --git a/apps/signal/54-pipe-observable-to-signal/src/app/product-row.component.ts b/apps/signal/54-pipe-observable-to-signal/src/app/product-row.component.ts
new file mode 100644
index 0000000..ce375e9
--- /dev/null
+++ b/apps/signal/54-pipe-observable-to-signal/src/app/product-row.component.ts
@@ -0,0 +1,34 @@
+import { AsyncPipe } from '@angular/common';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ inject,
+ Input,
+} from '@angular/core';
+import { CurrencyPipe } from './currency.pipe';
+import { CurrencyService } from './currency.service';
+import { Product } from './product.model';
+
+@Component({
+ standalone: true,
+ selector: 'tr[product-row]',
+ template: `
+ {{ productInfo.name }} |
+ {{ productInfo.priceA | currency | async }} |
+ {{ productInfo.priceB | currency | async }} |
+ {{ productInfo.priceC | currency | async }} |
+ `,
+ imports: [AsyncPipe, CurrencyPipe],
+ providers: [CurrencyService],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ProductRowComponent {
+ protected productInfo!: Product;
+
+ @Input({ required: true }) set product(product: Product) {
+ this.currencyService.updateCode(product.currencyCode);
+ this.productInfo = product;
+ }
+
+ currencyService = inject(CurrencyService);
+}
diff --git a/apps/signal/54-pipe-observable-to-signal/src/app/product.model.ts b/apps/signal/54-pipe-observable-to-signal/src/app/product.model.ts
new file mode 100644
index 0000000..174e7dc
--- /dev/null
+++ b/apps/signal/54-pipe-observable-to-signal/src/app/product.model.ts
@@ -0,0 +1,55 @@
+export interface Product {
+ name: string;
+ priceA: number;
+ priceB: number;
+ priceC: number;
+ currencyCode: string;
+}
+
+export const products: Product[] = [
+ {
+ name: 'bike',
+ priceA: 1000,
+ priceB: 2000,
+ priceC: 2200,
+ currencyCode: 'USD',
+ },
+ { name: 'tent', priceA: 112, priceB: 120, priceC: 41, currencyCode: 'EUR' },
+ {
+ name: 'sofa',
+ priceA: 500,
+ priceB: 422,
+ priceC: 5000,
+ currencyCode: 'EUR',
+ },
+ {
+ name: 'watch',
+ priceA: 50,
+ priceB: 130,
+ priceC: 150,
+ currencyCode: 'AUD',
+ },
+ {
+ name: 'computer',
+ priceA: 1000,
+ priceB: 2200,
+ priceC: 3500,
+ currencyCode: 'GBP',
+ },
+ { name: 'mug', priceA: 10, priceB: 15, priceC: 20, currencyCode: 'EUR' },
+ {
+ name: 'headset',
+ priceA: 100,
+ priceB: 150,
+ priceC: 220,
+ currencyCode: 'CAD',
+ },
+ { name: 'cable', priceA: 5, priceB: 10, priceC: 15, currencyCode: 'EUR' },
+ {
+ name: 'table',
+ priceA: 100,
+ priceB: 20,
+ priceC: 500,
+ currencyCode: 'EUR',
+ },
+];
diff --git a/apps/signal/54-pipe-observable-to-signal/src/assets/.gitkeep b/apps/signal/54-pipe-observable-to-signal/src/assets/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/apps/signal/54-pipe-observable-to-signal/src/favicon.ico b/apps/signal/54-pipe-observable-to-signal/src/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..317ebcb2336e0833a22dddf0ab287849f26fda57
GIT binary patch
literal 15086
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
+
+
+
+ signal-pipe-observable-to-signal
+
+
+
+
+
+
+
+
diff --git a/apps/signal/54-pipe-observable-to-signal/src/main.ts b/apps/signal/54-pipe-observable-to-signal/src/main.ts
new file mode 100644
index 0000000..31c5da4
--- /dev/null
+++ b/apps/signal/54-pipe-observable-to-signal/src/main.ts
@@ -0,0 +1,4 @@
+import { bootstrapApplication } from '@angular/platform-browser';
+import { AppComponent } from './app/app.component';
+
+bootstrapApplication(AppComponent).catch((err) => console.error(err));
diff --git a/apps/signal/54-pipe-observable-to-signal/src/styles.scss b/apps/signal/54-pipe-observable-to-signal/src/styles.scss
new file mode 100644
index 0000000..552f97d
--- /dev/null
+++ b/apps/signal/54-pipe-observable-to-signal/src/styles.scss
@@ -0,0 +1,26 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+/* You can add global styles to this file, and also import other style files */
+table {
+ width: 100%;
+}
+
+table thead > tr > th {
+ text-align: left;
+ padding: 1rem 1rem;
+ border: 1px solid #dee2e6;
+ border-width: 0 0 1px 0;
+ font-weight: 700;
+ color: #343a40;
+ background: #f8f9fa;
+ transition: box-shadow 0.2s;
+}
+
+table tbody > tr > td {
+ text-align: left;
+ border: 1px solid #dee2e6;
+ border-width: 0 0 1px 0;
+ padding: 1rem 1rem;
+}
diff --git a/apps/signal/54-pipe-observable-to-signal/tailwind.config.js b/apps/signal/54-pipe-observable-to-signal/tailwind.config.js
new file mode 100644
index 0000000..38183db
--- /dev/null
+++ b/apps/signal/54-pipe-observable-to-signal/tailwind.config.js
@@ -0,0 +1,14 @@
+const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind');
+const { join } = require('path');
+
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: [
+ join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'),
+ ...createGlobPatternsForDependencies(__dirname),
+ ],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+};
diff --git a/apps/signal/54-pipe-observable-to-signal/tsconfig.app.json b/apps/signal/54-pipe-observable-to-signal/tsconfig.app.json
new file mode 100644
index 0000000..5822042
--- /dev/null
+++ b/apps/signal/54-pipe-observable-to-signal/tsconfig.app.json
@@ -0,0 +1,10 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../../dist/out-tsc",
+ "types": []
+ },
+ "files": ["src/main.ts"],
+ "include": ["src/**/*.d.ts"],
+ "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"]
+}
diff --git a/apps/signal/54-pipe-observable-to-signal/tsconfig.editor.json b/apps/signal/54-pipe-observable-to-signal/tsconfig.editor.json
new file mode 100644
index 0000000..a8ac182
--- /dev/null
+++ b/apps/signal/54-pipe-observable-to-signal/tsconfig.editor.json
@@ -0,0 +1,6 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["src/**/*.ts"],
+ "compilerOptions": {},
+ "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"]
+}
diff --git a/apps/signal/54-pipe-observable-to-signal/tsconfig.json b/apps/signal/54-pipe-observable-to-signal/tsconfig.json
new file mode 100644
index 0000000..3df17b9
--- /dev/null
+++ b/apps/signal/54-pipe-observable-to-signal/tsconfig.json
@@ -0,0 +1,30 @@
+{
+ "compilerOptions": {
+ "target": "es2022",
+ "useDefineForClassFields": false,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.editor.json"
+ },
+ {
+ "path": "./tsconfig.app.json"
+ }
+ ],
+ "extends": "../../../tsconfig.base.json",
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}
diff --git a/challenge-number.json b/challenge-number.json
index f2a09fd..feedd16 100644
--- a/challenge-number.json
+++ b/challenge-number.json
@@ -1,6 +1,6 @@
{
- "total": 53,
+ "total": 54,
"🟢": 21,
"🟠": 122,
- "🔴": 209
+ "🔴": 210
}
diff --git a/docs/src/content/docs/challenges/signal/53-big-signal-performance.md b/docs/src/content/docs/challenges/signal/53-big-signal-performance.md
index 3e2b9dc..d3b4ea4 100644
--- a/docs/src/content/docs/challenges/signal/53-big-signal-performance.md
+++ b/docs/src/content/docs/challenges/signal/53-big-signal-performance.md
@@ -9,7 +9,6 @@ challengeNumber: 53
command: signal-big-signal-performance
sidebar:
order: 122
- badge: New
---
## Information
diff --git a/docs/src/content/docs/challenges/signal/54-pipe-observable-to-signal.md b/docs/src/content/docs/challenges/signal/54-pipe-observable-to-signal.md
new file mode 100644
index 0000000..a6952b0
--- /dev/null
+++ b/docs/src/content/docs/challenges/signal/54-pipe-observable-to-signal.md
@@ -0,0 +1,22 @@
+---
+title: 🔴 Pipe Observable to Signal
+description: Challenge 54 is about refactoring an application using observable to signals
+author: thomas-laforge
+contributors:
+ - tomalaforge
+challengeNumber: 54
+command: signal-pipe-observable-to-signal
+sidebar:
+ order: 210
+ badge: New
+---
+
+## Information
+
+We have a legacy application that is using observables to store a state. Signals are a very good fit for that.
+
+## Statement
+
+So the goal of this challenge is to refactor the following application to be a fully signal based application.
+
+Be careful along the way, everything might not work as you wish.
diff --git a/docs/src/content/docs/es/index.mdx b/docs/src/content/docs/es/index.mdx
index 8457c7a..06a25bf 100644
--- a/docs/src/content/docs/es/index.mdx
+++ b/docs/src/content/docs/es/index.mdx
@@ -13,7 +13,7 @@ hero:
icon: right-arrow
variant: primary
- text: Ir al Desafío más reciente
- link: /es/challenges/signal/53-big-signal-performance/
+ link: /es/challenges/signal/54-pipe-observable-to-signal/
icon: rocket
- text: Dar una estrella
link: https://github.com/tomalaforge/angular-challenges
@@ -26,8 +26,8 @@ import MyIcon from '../../../components/MyIcon.astro';
import SubscriptionForm from '../../../components/SubscriptionForm.astro';
-
- Este repositorio contiene 53 Desafíos relacionados con Angular, Nx, RxJS, Ngrx y Typescript.
+
+ Este repositorio contiene 54 Desafíos relacionados con Angular, Nx, RxJS, Ngrx y Typescript.
Estos desafíos se resuelven en torno a problemas de la vida real o características específicas para mejorar tus habilidades.
diff --git a/docs/src/content/docs/fr/index.mdx b/docs/src/content/docs/fr/index.mdx
index fe9eade..f2269f9 100644
--- a/docs/src/content/docs/fr/index.mdx
+++ b/docs/src/content/docs/fr/index.mdx
@@ -13,7 +13,7 @@ hero:
icon: right-arrow
variant: primary
- text: Aller au dernier Challenge
- link: /fr/challenges/signal/53-big-signal-performance/
+ link: /fr/challenges/signal/54-pipe-observable-to-signal/
icon: rocket
- text: Donne une étoile
link: https://github.com/tomalaforge/angular-challenges
@@ -26,8 +26,8 @@ import MyIcon from '../../../components/MyIcon.astro';
import SubscriptionForm from '../../../components/SubscriptionForm.astro';
-
- Ce répertoire rassemble 53 Défis liés à Angular, Nx, RxJS, Ngrx et Typescript. Ces défis portent sur des problèmes réels ou des fonctionnalités spécifiques pour améliorer vos compétences.
+
+ Ce répertoire rassemble 54 Défis liés à Angular, Nx, RxJS, Ngrx et Typescript. Ces défis portent sur des problèmes réels ou des fonctionnalités spécifiques pour améliorer vos compétences.
diff --git a/docs/src/content/docs/pt/index.mdx b/docs/src/content/docs/pt/index.mdx
index 4620405..cd06b47 100644
--- a/docs/src/content/docs/pt/index.mdx
+++ b/docs/src/content/docs/pt/index.mdx
@@ -13,7 +13,7 @@ hero:
icon: right-arrow
variant: primary
- text: Ir para o desafio mais recente
- link: /pt/challenges/signal/53-big-signal-performance/
+ link: /pt/challenges/signal/54-pipe-observable-to-signal/
icon: rocket
- text: Dar uma estrela
link: https://github.com/tomalaforge/angular-challenges
@@ -26,8 +26,8 @@ import MyIcon from '../../../components/MyIcon.astro';
import SubscriptionForm from '../../../components/SubscriptionForm.astro';
-
- Este repositório possui 53 Desafios relacionados a Angular, Nx, RxJS,
+
+ Este repositório possui 54 Desafios relacionados a Angular, Nx, RxJS,
Ngrx e Typescript.
Esses desafios são voltados para problemas reais ou funcionalidades específicas afim de
melhorar suas habilidades.
diff --git a/docs/src/content/docs/ru/index.mdx b/docs/src/content/docs/ru/index.mdx
index 0802527..e0d5456 100644
--- a/docs/src/content/docs/ru/index.mdx
+++ b/docs/src/content/docs/ru/index.mdx
@@ -13,7 +13,7 @@ hero:
icon: right-arrow
variant: primary
- text: Перейти к последней задаче
- link: /ru/challenges/signal/53-big-signal-performance/
+ link: /ru/challenges/signal/54-pipe-observable-to-signal/
icon: rocket
- text: Добавить звезду
link: https://github.com/tomalaforge/angular-challenges
@@ -26,8 +26,8 @@ import MyIcon from '../../../components/MyIcon.astro';
import SubscriptionForm from '../../../components/SubscriptionForm.astro';
-
- Этот репозиторий содержит 53 испытаний, связанных с Angular, Nx, RxJS, Ngrx и Typescript.
+
+ Этот репозиторий содержит 54 испытаний, связанных с Angular, Nx, RxJS, Ngrx и Typescript.
Испытания основаны на реальных задачах или инструментах для того, чтобы прокачать вас.
diff --git a/libs/shared/ui/src/lib/table.component.ts b/libs/shared/ui/src/lib/table.component.ts
index 162c8cd..18b4f88 100644
--- a/libs/shared/ui/src/lib/table.component.ts
+++ b/libs/shared/ui/src/lib/table.component.ts
@@ -1,21 +1,20 @@
-import { NgFor, NgTemplateOutlet } from '@angular/common';
+import { NgTemplateOutlet } from '@angular/common';
import { Component, ContentChild, Input, TemplateRef } from '@angular/core';
@Component({
selector: 'table',
standalone: true,
- imports: [NgTemplateOutlet, NgFor],
+ imports: [NgTemplateOutlet],
template: `
-
-
-
+ @for (item of items; track $index) {
+
+
+
+ }
`,
})
export class TableComponent {