Yêu cầu chức năng
Một giao diện người dùng đơn giản gồm ba ô nhập liệu kiểu văn bản và một nhãn hiển thị kết quả. Giá trị của nhãn phải cập nhật liên tục dựa trên tổng số học của ba giá trị đầu vào. Các giá trị không hợp lệ (không phải số) được xử lý như 0. Giá trị khởi tạo cho ba ô lần lượt là "1", "2", và "3".
Tạo dự án Angular cơ bản
Đảm bảo đã cài đặt Node.js, sau đó thực hiện:
npm install -g @angular/cli<br>ng new ReactiveSumApp --strict=false --routing=false --style=css<br>cd ReactiveSumApp<br>npm install
Sau khi tạo xong, mở dự án trong trình soạn thảo hỗ trợ TypeScript (ví dụ: VS Code hoặc WebStorm). Chạy ứng dụng bằng lệnh:
ng serve
Truy cập http://localhost:4200 để kiểm tra.
Cập nhật CSS
Chỉnh sửa src/app/app.component.css để căn lề và định dạng ô nhập liệu:
.input-field {<br> width: 60px;<br> text-align: center;<br> padding: 4px;<br> font-size: 14px;<br>}
Cách tiếp cận truyền thống (không dùng RxJS)
Thêm FormsModule vào app.module.ts:
import { NgModule } from '@angular/core';<br>import { BrowserModule } from '@angular/platform-browser';<br>import { FormsModule } from '@angular/forms';<br><br>import { AppComponent } from './app.component';<br><br>@NgModule({<br> declarations: [AppComponent],<br> imports: [BrowserModule, FormsModule],<br> bootstrap: [AppComponent]<br>)<br>export class AppModule { }
Cập nhật template app.component.html:
<div class="container"><br> <h2>Tổng động ba số</h2><br> <p><br> <input class="input-field" [(ngModel)]="valA" (input)="updateTotal()"><br> +<br> <input class="input-field" [(ngModel)]="valB" (input)="updateTotal()"><br> +<br> <input class="input-field" [(ngModel)]="valC" (input)="updateTotal()"><br> =<br> <span class="result">{{ total }}</span><br> </p><br></div>
Và logic trong app.component.ts:
import { Component } from '@angular/core';<br><br>@Component({<br> selector: 'app-root',<br> templateUrl: './app.component.html',<br> styleUrls: ['./app.component.css']<br>)<br>export class AppComponent {<br> valA = '1';<br> valB = '2';<br> valC = '3';<br> total = '6';<br><br> updateTotal(): void {<br> const parseSafe = (s: string): number => {<br> const num = Number(s);<br> return isNaN(num) ? 0 : num;<br> };<br> this.total = String(parseSafe(this.valA) + parseSafe(this.valB) + parseSafe(this.valC));<br> }<br>}
Cách tiếp cận phản ứng với RxJS
Thay đổi template để loại bỏ ràng buộc hai chiều và sử dụng tham chiếu DOM:
<div class="container"><br> <h2>Tổng động ba số (RxJS)</h2><br> <p><br> <input #inputA class="input-field" value="1"><br> +<br> <input #inputB class="input-field" value="2"><br> +<br> <input #inputC class="input-field" value="3"><br> =<br> <span class="result">{{ sum$ | async }}</span><br> </p><br></div>
Cập nhật component với các import cần thiết và cấu hình luồng dữ liệu:
import { Component, AfterViewInit, ViewChild, ElementRef } from '@angular/core';<br>import { Observable, combineLatest, fromEvent } from 'rxjs';<br>import { map, pluck, startWith, distinctUntilChanged } from 'rxjs/operators';<br><br>@Component({<br> selector: 'app-root',<br> templateUrl: './app.component.html',<br> styleUrls: ['./app.component.css']
Lưu ý rằng việc sử dụng distinctUntilChanged() giúp tránh phát ra giá trị trùng lặp — tối ưu hiệu năng khi người dùng nhấn phím không làm thay đổi nội dung (ví dụ: di chuyển con trỏ).