Computer >> Máy Tính >  >> Lập trình >> Ruby

Sử dụng Angular với Rails 5

Bạn đã nghe câu chuyện trước đây. Bạn đã có một ứng dụng chạy trên các API back-end phân quyền và hoạt động đầy đủ của bạn và một front-end được tạo bằng bất kỳ bộ công cụ thông thường nào.

Bây giờ, bạn muốn chuyển sang Angular. Hoặc, có lẽ bạn chỉ đang tìm cách tích hợp Angular với các dự án Rails của mình bởi vì bạn thích mọi thứ theo cách này. Chúng tôi không đổ lỗi cho bạn.

Với cách tiếp cận như vậy, bạn có thể tận dụng lợi thế của cả hai thế giới và quyết định xem bạn muốn sử dụng các tính năng từ Rails hay Angular để định dạng nội dung chẳng hạn.

Những gì chúng tôi sẽ xây dựng

Không cần phải lo lắng. Hướng dẫn này được viết cho mục đích này. Chúng tôi sẽ đi sâu vào việc tạo ra một ứng dụng CRUD hoạt động đầy đủ trên một miền người dùng.

Ở phần cuối của bài viết, bạn sẽ biết một số khái niệm cơ bản về Angular và cách thiết lập một dự án back-end Rails tích hợp trực tiếp với Angular cho front-end, như hình dưới đây:

Sử dụng Angular với Rails 5 CRUD của người dùng được tạo bằng Rails và Angular

Ứng dụng sẽ xử lý tất cả bốn hoạt động CRUD trên miền của người dùng được truy xuất từ ​​dịch vụ web kiểm tra giả mạo bên ngoài. Ứng dụng sẽ được xây dựng trên nền tảng kiến ​​trúc MVC, với mỗi lớp Angular được giải thích chi tiết để giúp bạn hiểu rõ hơn về cách mọi thứ liên kết với nhau. Phong cách tùy thuộc vào Bootstrap.

Thiết lập

Như bạn có thể đoán, chúng tôi sẽ cần phần mềm sau:

  • Ruby (Tôi đã chọn phiên bản 2.7.0preview1),
  • Ruby and Rails (Tôi đang sử dụng phiên bản 5.0.7.2 của nó),
  • Node.js (Tôi đang sử dụng v13.7.0),
  • Yarn (Ít nhất là phiên bản 1.22.4)

Đảm bảo cài đặt mọi thứ đúng cách. Sau đó, chúng ta có thể chuyển sang dự án. Chọn một thư mục tùy chọn của bạn và chạy lệnh sau:

rails new crud-rails-angular

Chờ thiết lập hoàn tất và mở dự án trong IDE yêu thích của bạn. Chúng tôi sẽ làm việc với VS Code cho bài viết này vì nó đơn giản, mạnh mẽ và bao hàm cả cú pháp Rails và Angular một cách trơn tru.

Nếu bạn đã sử dụng Rails 5 một thời gian, bạn có thể nhận thấy rằng new của nó lệnh tạo ra một lỗi trong Gemfile cho cấu hình SQLite. Nó không có phiên bản tối thiểu, và điều đó sẽ làm cho nó chạy với lỗi. Hãy khắc phục sự cố này bằng cách cập nhật nó lên

gem 'sqlite3', '~> 1.3.10'

Hoàn hảo!

Thiết lập Webpacker

Cách tốt nhất để quản lý các ứng dụng giống JavaScript trong Rails là thông qua Webpacker. Nó sử dụng Webpack đằng sau hậu trường để cung cấp các tính năng, chẳng hạn như tiền xử lý và gói các ứng dụng JavaScript, như Angular, vào một ứng dụng Rails hiện có.

Để cài đặt nó, chỉ cần thêm một dòng mới vào Gemfile của bạn :

gem 'webpacker', '~> 4.3.x'

Điều này sẽ đảm bảo rằng bạn sẽ cài đặt một phiên bản mới nhất. Tiếp theo, chạy các lệnh sau:

bundle install
bundle exec rake webpacker:install
bundle exec rake webpacker:install:angular

Lệnh đầu tiên sẽ tải xuống và cập nhật các phần phụ thuộc Rails đã thêm.

Cái thứ hai tương đương với npm install vì nó tạo ra node_modules thư mục và cài đặt một loạt các phụ thuộc Angular bắt buộc, chẳng hạn như Babel, Sass, Browserlist và Webpack. Bây giờ, chúng ta có cả ứng dụng Node và Rails trong cùng một dự án.

Trong lệnh mới nhất, chúng ta có lệnh tương đương với npm install angular , sẽ tải xuống tất cả các phụ thuộc Angular bắt buộc và làm cho nó hoạt động cùng với dự án Rails của chúng tôi.

Ở cuối các lệnh này, bạn cũng có thể thấy package.json tệp được tạo. Tất cả các phần phụ thuộc bắt buộc của chúng tôi đều được đặt ở đó và bạn có thể thêm bất kỳ phần nào bạn cần trong tương lai.

Ngoài ra, một số thư mục và tệp đã được tạo trong / app thư mục, chẳng hạn như / javascript mới . Trong thư mục này, bạn đã có một / hello_angular thư mục được tạo để hỗ trợ sự khởi đầu của quá trình phát triển của bạn.

Để có thêm thời gian, tôi sẽ yêu cầu bạn phản chiếu cấu trúc thư mục và tệp của bạn với cấu trúc sau:

Sử dụng Angular với Rails 5

Một số Điều chỉnh Góc

Webpacker đề xuất một loạt các điều chỉnh trong dự án Rails đã tạo của bạn. Vì vậy, hãy dành chút thời gian để sắp xếp ngôi nhà.

Trước tiên, hãy mở application.js của bạn tệp được đặt trong / pack thư mục (hiển thị trong hình trên) và thêm mã sau:

import "core-js/stable";
import "regenerator-runtime/runtime";

Những lần nhập này hoạt động như một lực lượng phụ trợ để ổn định môi trường JavaScript trong dự án Rails.

Bây giờ, chúng ta cần thông báo cho Rails từ nơi nó phải chọn đầu ra cho các trang của nó. Khi Webpacker hoàn thành việc đóng gói mọi thứ, nó sẽ tạo ra một loạt các tệp tĩnh có thể phân phối mà Rails phải biết.

Truy cập application.html.erb tệp trong ứng dụng / chế độ xem / bố cục và thay đổi <head> của nó gắn thẻ nội dung vào phần sau:

<head>
  <title>CrudRailsAngular</title>
  <base href="/" />
  <!-- 1 -->
  <%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous" />
  <!-- 2 -->
  <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag 'application' %>
  <!-- 3 -->
</head>

Hãy phân tích điều này một chút:

  1. Ở đây, chúng tôi đang thêm base thẻ này cho Rails biết vị trí cần tìm khi ứng dụng khởi động.
  2. Chúng tôi sẽ sử dụng Bootstrap để phỏng đoán phong cách cho trang, vì vậy chúng tôi chỉ có thể tập trung vào việc triển khai.
  3. Đây là nơi bạn phải đặt thẻ Webpacker ánh xạ tới / pack nội dung thư mục (giống nội dung sẽ được Webpacker tạo tự động sau mỗi lần biên dịch).

Mô hình và Cơ sở dữ liệu

Chuyển sang thiết lập cơ sở dữ liệu. Để làm cho mọi thứ nhanh hơn, chúng tôi sẽ giới thiệu một mô hình mới có tên là User . Đây là lệnh bạn phải chạy để đạt được nó:

rails g scaffold User name:string age:integer address:text && rake db:migrate

Nó sẽ tạo tất cả các thư mục và tệp trong mô hình của chúng tôi, chúng tôi sẽ cần để Rails thao tác thông tin cơ sở dữ liệu (từ SQLite) và lưu trữ nó vào các hoạt động CRUD của chúng tôi.

Sau đó, bạn sẽ thấy rằng một tệp mới XXX1_create_users.rb được tạo theo db / migrate / thư mục. Mở nó và bạn sẽ thấy CreateUsers mới được tạo ghi lại.

Trong ứng dụng / mô hình / thư mục, bạn sẽ thấy User được tạo sau đó mô hình tại user.rb tệp.

Bây giờ, hãy mở db / seed.rb tệp và thêm mã sau:

User.create(name: 'Luke Wan', age: 23, address: '123 Test St.')
User.create(name: 'Mary Poppins', age: 41, address: '123 ABC St.')
User.create(name: 'John Neilman', age: 76, address: '000 Test St.')

Mã này sẽ khởi tạo User của chúng tôi bảng với một số dữ liệu khi khởi động. Lưu nó và chạy lệnh:

rake db:seed

Thao tác này sẽ bắt đầu bảng thông qua các lệnh được liệt kê ở trên. Tiếp theo, bạn có thể nhập cơ sở dữ liệu SQLite và kiểm tra xem cơ sở dữ liệu đó có hoạt động hay không bằng cách ra lệnh:

sqlite3 db/development.sqlite3

Sau đó, chọn dữ liệu bảng:

select * from users;

và bạn có thể thấy kết quả.

Thành phần Người dùng

Bạn sẽ cần cài đặt thêm một số phụ thuộc để giúp chuyển đổi HTML và CSS sang các trang Rails của chúng tôi; thêm bộ định tuyến Angular, biểu mẫu libs và ngx-bootstrap, mà chúng tôi sẽ sử dụng để tạo điều kiện thuận lợi cho việc tạo và thao tác các thành phần Bootstrap. Vì vậy, hãy phát hành lệnh sau:

yarn add @angular/router @angular/forms html-loader css-loader ngx-bootstrap

Tuy nhiên, trước khi chúng ta tìm hiểu mã thành phần, có một số khái niệm quan trọng mà chúng ta cần chỉ ra, bắt đầu với cấu trúc giải phẫu của một thành phần Angular.

Thành phần là gì?

Trong Angular, một thành phần tồn tại để kết nối các khung nhìn của bạn với logic ứng dụng được tạo trong TypeScript.

Nói cách khác, một thành phần giống như một thùng chứa tất cả logic mà các khung nhìn của bạn cần để hỗ trợ hoạt động của nó. Nó xác định các giá trị mà các khung nhìn sẽ trình bày và kiểm soát các luồng của chúng. Nó tương đương với một "controller" trong các khuôn khổ tương tự.

Để tạo một thành phần, tất cả những gì bạn cần làm là xác định một lớp mới, triển khai OnInit giao diện và chú thích lớp bằng @Component người trang trí:

export class UserIndexComponent implements OnInit {
    constructor() { ... }

    ngOnInit() { ... }
}

@ Component và OnInit

@Component decorator rất quan trọng vì nó đánh dấu lớp này là một thành phần Angular dễ nhận biết và cung cấp các cấu hình siêu dữ liệu giúp Angular giải quyết chúng liên quan đến quá trình xử lý, khởi tạo và sử dụng trong thời gian chạy.

Thực hiện các cấu hình siêu dữ liệu sau:

@Component({
    selector: "users",
    template: templateString,
})

Tại đây, selector nói với Angular rằng giá trị được cung cấp là bộ chọn CSS mà nó có thể sử dụng để xác định chỉ thị hiện tại thành một mẫu; vâng, đó là cùng một mẫu được cung cấp trong thuộc tính siêu dữ liệu tiếp theo.

OnInit Tuy nhiên, giao diện là tùy chọn và đó là một cách tốt để khởi tạo nội dung trước khi thành phần kết thúc vòng đời của nó. Nó hoạt động giống như một phương pháp hậu cấu trúc.

Truyền phụ thuộc

Angular là một DI ( Dependency Injection ) khuôn khổ, một đặc tính giúp tăng tính mô-đun và năng suất của nó.

Sự phụ thuộc trong Angular có thể thay đổi từ các dịch vụ và kho lưu trữ của bạn cho đến bất kỳ loại đối tượng thông thường nào mà bạn cảm thấy phù hợp để đưa vào một nơi khác trong mã.

Để biến một lớp thành "có thể tiêm", bạn chỉ cần chú thích nó bằng @Injectable người trang trí:

@Injectable({
    providedIn: "root",
})
export class UserService {
    ...
}

providedIn cho biết kim phun nào sẽ cung cấp thuốc tiêm mà bạn đang tạo. root giá trị cho Angular biết rằng kim phun phải là cấp ứng dụng. Bạn có thể xem thêm tại đây.

Ví dụ:để đưa lớp vào một thành phần, bạn yêu cầu Angular thực hiện điều đó trong phương thức khởi tạo của thành phần:

constructor(
    private userService: UserService,
) {}

Nó đơn giản như vậy!

Thành phần đã hoàn thành

Dưới đây, bạn có thể tìm thấy danh sách mã cuối cùng cho thành phần Người dùng của chúng tôi. Đặt nó vào index.component.ts , trong javascript / hello_angular / app / thư mục.

import { Component, OnInit, TemplateRef } from "@angular/core";
import { FormGroup, FormBuilder } from "@angular/forms";
import { BsModalRef, BsModalService } from "ngx-bootstrap/modal";

import templateString from "./index.component.html";
import { UserService } from "../user.service";
import { User } from "../user.class";

@Component({
  selector: "users",
  template: templateString,
})
export class UserIndexComponent implements OnInit {
  users: User[];
  modalRef: BsModalRef;
  userForm: FormGroup;
  isNew: Boolean;

  constructor(public fb: FormBuilder, private userService: UserService, private modalService: BsModalService) {}

  public newUser(template: TemplateRef<any>) {
    this.reset();
    this.modalRef = this.modalService.show(template);
  }

  public createUser() {
    this.userService.create(this.userForm.value).subscribe(() => {
      console.log("User created!");
      this.reset();

      this.modalRef.hide();
    });
  }

  public editUser(user, template: TemplateRef<any>) {
    this.isNew = false;
    this.userForm = this.fb.group({
      id: [user.id],
      name: [user.name],
      age: [user.age],
      address: [user.address],
    });

    this.modalRef = this.modalService.show(template);
  }

  public updateUser() {
    const { id } = this.userForm.value;
    this.userService.update(id, this.userForm.value).subscribe(() => {
      console.log("User updated!");
      this.reset();

      this.modalRef.hide();
    });
  }

  public deleteUser(id) {
    if (confirm("Are you sure?")) {
      this.userService.delete(id).subscribe(() => {
        console.log("User deleted!");
        this.reset();
      });
    }
  }

  ngOnInit() {
    this.reset();
  }

  public reset() {
    this.isNew = true;
    this.userService.getUsers().subscribe((users) => {
      this.users = users;
    });

    this.userForm = this.fb.group({
      id: [""],
      name: [""],
      age: [""],
      address: [""],
    });
  }
}

users mảng sẽ giữ dữ liệu bảng hiện tại được liệt kê trên màn hình và được truy xuất từ ​​reset đến lượt nó, gọi API Rails của chúng tôi qua UserService (sẽ được tạo).

userForm chỉ là một tham chiếu để giúp tạo và cập nhật người dùng của chúng tôi vì cùng một biểu mẫu sẽ được sử dụng cho cả hai hoạt động. isNew cũng giúp làm điều đó, xác định dòng chảy mà chúng ta đang tham gia vào thời điểm hiện tại.

Ở đây, chúng tôi có một phương pháp tương đương CRUD cho mỗi hoạt động. Mỗi người trong số họ gọi UserService tương ứng phương thức để cam kết quy trình trong API Rails.

Chúng tôi cũng sẽ cần thiết lập mô-đun HTML để chuyển đổi các mẫu của chúng tôi sang HTML (chúng tôi sẽ sớm xem thêm về mô-đun). Vì vậy, hãy mở html.d.ts tệp trong cùng một thư mục và thêm:

declare module "*.html" {
  const content: string;
  export default content;
}

Dịch vụ và Mô hình Angular

Hãy chuyển sang UserService của Angular sự sáng tạo. Angular là một framework, giống như Rails. Vì vậy, điều đó có nghĩa là bạn có thể tuân theo các quy tắc của họ ngay cả khi điều này có nghĩa là có các mô hình trùng lặp (hoặc rất giống nhau) chẳng hạn.

Mô hình là gì?

Mô hình góc là các đối tượng đơn giản chứa các thuộc tính dữ liệu có ý nghĩa với nhau (nghĩa là chúng đại diện cho một phần ngắn gọn trong miền của bạn). Chúng giống như bất kỳ mô hình nào khác trong hầu hết các ngôn ngữ và khuôn khổ.

Việc tập trung dữ liệu của bạn ở một nơi sẽ giúp ích rất nhiều cho việc sao chép dữ liệu trong toàn bộ mã như chúng tôi làm với mô hình người dùng của mình:

export class User {
  constructor(public id: number, public name: string, public age: number, public address: string) {}
}

Hãy nhớ rằng đó là TypeScript, vì vậy các thuộc tính của mô hình của bạn phải luôn có một kiểu được xác định.

Tạo một tệp mới có tên là user.class.ts trong javascript / hello_angular / app / user / và đặt mã ở trên vào đó.

Còn về Dịch vụ thì sao?

Dịch vụ là một khái niệm rộng, nhưng chúng ta có thể hiểu chúng như những đối tượng được xác định rõ ràng và có mục đích. Chúng giúp các thành phần có logic phức tạp hơn, cung cấp cho chúng dữ liệu đã được xử lý và chuyển đổi, thường đến từ dịch vụ bên ngoài hoặc cơ sở dữ liệu.

Một dịch vụ không cần bất kỳ chú thích hoặc giao diện cụ thể nào; bạn chỉ cần tạo một lớp và làm cho nó có thể tiêm được , như chúng ta đã thấy trước đây. Sau đó, bạn có thể đưa nó vào các thành phần của mình.

Dịch vụ có thể quan sát được

Một tính năng thú vị khác của Angular là nó cho phép bạn sử dụng RxJS với các lớp của mình.

Ví dụ:máy khách HTTP mặc định của Angular, giống máy khách mà chúng tôi sẽ sử dụng để tìm nạp thông tin từ một dịch vụ bên ngoài, trả về RxJS Observables . Đây là lý do tại sao khi bạn gọi bất kỳ UserService nào của chúng tôi trong thành phần người dùng, bạn có thể subscribe đến Observable kết quả:

this.userService.getUsers().subscribe((users) => {
  this.users = users;
});

Lưu ý rằng nếu bạn không quen thuộc với RxJS, tôi thực sự khuyên bạn nên đọc sơ qua tài liệu của nó; nó không khó lắm!;)

Xin nhắc lại, trong javascript / hello_angular / app / user / thư mục, tạo một tệp khác có tên là user.service.ts . Đây là nội dung của nó:

import { Injectable } from "@angular/core";
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { map } from "rxjs/operators";
import { Observable } from "rxjs";

import { User } from "./user.class";

@Injectable({
  providedIn: "root",
})
export class UserService {
  constructor(private http: HttpClient) {}

  httpOptions = {
    headers: new HttpHeaders({
      "Content-Type": "application/json",
    }),
  };

  getUsers(): Observable<User[]> {
    return this.http.get("/users.json").pipe(
      map((users: User[]) =>
        users.map((user) => {
          return new User(user.id, user.name, user.age, user.address);
        })
      )
    );
  }

  create(user): Observable<User> {
    return this.http.post<User>("/users.json", JSON.stringify(user), this.httpOptions);
  }

  update(id, user): Observable<User> {
    return this.http.put<User>("/users/" + id + ".json", JSON.stringify(user), this.httpOptions);
  }

  delete(id) {
    return this.http.delete<User>("/users/" + id + ".json", this.httpOptions);
  }
}

Bạn có thể phát hiện ra những điểm tương đồng giữa thành phần này và thành phần chúng tôi vừa tạo không? Điều này là do chúng tôi cần các hoạt động tương ứng để hỗ trợ các hoạt động trong thành phần.

Lưu ý rằng HttpClient cũng phải được đưa vào bên trong phương thức khởi tạo của lớp, vì vậy chúng tôi có thể sử dụng nó cùng với lớp.

Mỗi hoạt động thực hiện một cuộc gọi HTTP tới API Rails của chúng tôi, một hoạt động được tạo tự động.

Lượt xem

Angular làm việc với các mẫu cho các khung nhìn của nó. Mẫu là một loại hỗn hợp HTML và JavaScript có thứ bậc cho Angular biết cách hiển thị từng thành phần.

Tuy nhiên, trước khi đi xa hơn với việc xây dựng chế độ xem của chúng tôi, trước tiên chúng ta hãy hiểu cách Angular chia nhỏ hệ thống mẫu của nó.

Chỉ thị góc cạnh

Vì các mẫu Angular về cơ bản là động, một số chỉ thị cần thiết để thúc đẩy Angular thông qua cách phù hợp để hiển thị nội dung.

Các chỉ thị chỉ đơn giản là các lớp có @Directive trang trí, giống như các thành phần. Có, @Component kế thừa từ @Directive , vì vậy nó cũng chính thức là một chỉ thị.

Tuy nhiên, có hai loại khác: cấu trúc thuộc tính chỉ thị.

Chỉ thị về cấu trúc

Các chỉ thị này đại diện cho các cấu trúc có điều kiện và vòng lặp được dịch từ JavaScript sang mẫu Angular. Chúng giúp làm cho mẫu trở nên năng động nhất có thể, giống như nếu bạn đang lập trình trong mã JavaScript vani của mình. Lấy ví dụ sau:

<tr *ngFor="let user of users">
  <td>{{ user.name }}</td>
</tr>

Các *ngFor chỉ thị yêu cầu Angular lặp lại trên mảng users và in tên của từng người dùng vào DOM.

Chỉ thị thuộc tính

Những điều này hoạt động trực tiếp với sự xuất hiện hoặc hành vi của các phần tử. Lấy ví dụ sau:

<form [formGroup]="userForm" (ngSubmit)="isNew ? createUser() : updateUser()" novalidate></form>

Ở đây, chúng tôi đang sửa đổi hành vi của biểu mẫu bằng cách đặt submit có điều kiện chức năng và sử dụng FormGroup của Angular để liên kết dữ liệu từng đầu vào biểu mẫu.

Data Binding

Tạo biểu mẫu với các khuôn khổ web có thể là một công việc phức tạp và dễ xảy ra lỗi nếu nó không cung cấp liên kết dữ liệu.

Angular hỗ trợ liên kết dữ liệu hai chiều, có nghĩa là bạn có thể kết nối trực tiếp các phần mẫu của mình với thành phần và ngược lại.

Biểu mẫu trên là một ví dụ điển hình về FormGroup sức mạnh ràng buộc dữ liệu. Nó tự động liên kết từng trường biểu mẫu với userForm đối tượng được tạo trong thành phần của chúng tôi.

Trong editUser ví dụ:bạn có thể thấy phiên bản đối diện của liên kết, trong đó userForm Các giá trị của được đặt trong thành phần và sẽ phản ánh biểu mẫu trên khung nhìn.

Tạo Chế độ xem Chỉ mục

Hãy chia nhỏ nội dung cho index.component.html thành hai phần. Đây là cái đầu tiên:

<div class="container pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
  <h1 class="display-4">User's Listing</h1>
  <p class="lead">A quick CRUD example of how to integrate Rails with Angular</p>

  <table class="table">
    <tr>
      <th>Id</th>
      <th>Name</th>
      <th>Age</th>
      <th>Address</th>
      <th>Actions</th>
    </tr>

    <tbody>
      <tr *ngFor="let user of users">
        <td>{{ user.id }}</td>
        <td>{{ user.name }}</td>
        <td>{{ user.age }}</td>
        <td>{{ user.address }}</td>
        <td colspan="2">
          <button class="btn btn-secondary" (click)="editUser(user, template)">Edit</button>
          |
          <button class="btn btn-danger" (click)="deleteUser(user.id)">Delete</button>
        </td>
      </tr>
    </tbody>
  </table>

  <button class="btn btn-primary float-right mt-4" (click)="newUser(template)">Insert New</button>
</div>

Hầu hết nó bao gồm HTML thuần túy. Chúng tôi sẽ không đi vào chi tiết về các lớp Bootstrap.

Phần quan trọng ở đây là ngFor chỉ thị trên hàng của bảng. Nó giúp lặp qua users mảng (nhớ không?) in từng thuộc tính của nó vào đầu ra HTML thông qua {{ … }} nhà điều hành.

Bất cứ khi nào bạn muốn thêm một trong các sự kiện DOM, như onClick , chỉ cần bọc tên sự kiện bằng dấu ngoặc đơn và thêm hàm thành phần mà nó sẽ gọi khi được nhấp vào.

Tạo Chế độ xem Phương thức

Phần thứ hai liên quan đến nội dung phương thức, vì vậy hãy thêm nó vào bên dưới phần trước:

<ng-template #template>
  <div class="modal-header">
    <h4 class="modal-title pull-left">{{ isNew ? "New User" : "Update User" }}</h4>
    <button type="button" class="close pull-right" aria-label="Close" (click)="modalRef.hide()">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
  <div class="modal-body">
    <form [formGroup]="userForm" (ngSubmit)="isNew ? createUser() : updateUser()" novalidate>
      <input type="hidden" formControlName="id" class="form-control" />
      <div class="form-group">
        <label>Name</label>
        <input type="text" formControlName="name" class="form-control" />
      </div>
      <div class="form-group">
        <label>Age</label>
        <input type="text" formControlName="age" class="form-control" />
      </div>
      <div class="form-group">
        <label>Address</label>
        <textarea class="form-control" formControlName="address" rows="3"></textarea>
      </div>

      <button type="submit" class="btn btn-primary">Submit</button>
    </form>
  </div>
</ng-template>

Lưu ý rằng chúng tôi đang sử dụng <ng-template> , cho phép bạn liên kết các phần tử giữa HTML và Angular. ID mẫu nằm ngay sau # ký tên.

Trong biểu mẫu, cũng lưu ý rằng chúng tôi đang sử dụng isNew biến thành phần để xác minh xem việc sử dụng biểu mẫu này hiện tại có liên quan đến việc tạo hoặc cập nhật của người dùng hay không.

Cuối cùng, chúng ta cần tiêm toàn bộ hello_angular ứng dụng vào Rails index.html.erb trang. Vì vậy, hãy mở tệp này trong lượt xem / người dùng / và thay đổi nội dung của nó thành như sau:

<hello-angular>We're almost done...</hello-angular> <%= javascript_pack_tag 'hello_angular' %>

Mô-đun góc

Bây giờ, chúng ta cần cho Angular biết nơi để tìm những thứ cần tìm. Nó xảy ra trong cấu hình mô-đun của nó.

Hãy bắt đầu bằng cách thêm nội dung vào app-bootstrap.module.ts :

import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";

import { ModalModule } from "ngx-bootstrap/modal";

@NgModule({
  imports: [CommonModule, ModalModule.forRoot()],
  exports: [ModalModule],
})
export class AppBootstrapModule {}

Điều này bị hạn chế đối với các thành phần Bootstrap mà chúng tôi đang kế thừa từ ngx-bootstrap. Thành phần duy nhất mà chúng tôi đang sử dụng lúc này là phương thức Bootstrap.

Sau đó, mở app-routing.module.ts và thay đổi nội dung của nó thành như sau:

import { RouterModule, Routes } from "@angular/router";
import { NgModule } from "@angular/core";

import { UserIndexComponent } from "./user/index/index.component";

const appRoutes: Routes = [
  { path: "users", component: UserIndexComponent },
  { path: "", redirectTo: "/users", pathMatch: "full" },
];

@NgModule({
  imports: [RouterModule.forRoot(appRoutes, { scrollPositionRestoration: "enabled" })],
  exports: [RouterModule],
})
export class AppRoutingModule {}

Điều này sẽ đảm bảo rằng Angular khớp với đúng thành phần của Người dùng khi / người dùng đường dẫn được gọi.

Và cuối cùng, đăng ký tất cả chúng trong AppModule chính lớp. Mở app.module.ts và đảm bảo rằng nó trông giống như sau:

import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { HttpClientModule } from "@angular/common/http";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";

import { AppComponent } from "./app.component";
import { AppRoutingModule } from "./app-routing.module";
import { AppBootstrapModule } from "./app-boostrap.module";
import { UserIndexComponent } from "./user/index/index.component";

@NgModule({
  declarations: [AppComponent, UserIndexComponent],
  imports: [HttpClientModule, AppRoutingModule, BrowserModule, FormsModule, ReactiveFormsModule, AppBootstrapModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

Tại đây, mọi thứ đã được lập bản đồ. Từ biểu mẫu của chúng tôi, ứng dụng khách HTTP và thành phần người dùng đến cấu hình mô-đun Bootstrap và định tuyến.

Hoàn thiện cấu hình

Trước khi bắt đầu thử nghiệm, chúng ta cần hoàn thành một số nội dung, bắt đầu với app.component.ts tệp:

import { Component } from "@angular/core";

@Component({
  selector: "hello-angular",
  template: "<router-outlet></router-outlet>",
})
export class AppComponent {
  name = "Angular!";
}

Thành phần ứng dụng chính cần biết cách định tuyến các đường dẫn, vì vậy RouterOutlet sẽ thực hiện công việc.

Sau đó, chúng tôi cần đảm bảo rằng Webpacker hiểu tiện ích mở rộng HTML mà chúng tôi đang làm việc cho đến nay. Đối với điều này, hãy mở webpacker.yml và trong / config thư mục, tìm kiếm các tiện ích mở rộng và thêm mục sau:

- .html

Webpacker chỉ nhận dạng bộ nạp TypeScript được tích hợp sẵn đi kèm với Angular theo mặc định. Chúng tôi cần xử lý HTML, đó là lý do tại sao trước đây chúng tôi đã cài đặt html-loader sự phụ thuộc. Để thiết lập, hãy mở environment.js tệp, trong config / webpack và thêm cấu hình trình tải sau:

environment.loaders.append("html", {
  test: /\.html$/,
  use: [
    {
      loader: "html-loader",
      options: {
        minimize: true,
      },
    },
  ],
});

Cuối cùng, để ngăn dịch vụ Angular của chúng tôi nhận được lỗi trên các cuộc gọi HTTP của chúng, chúng tôi cần tắt kiểm tra mã thông báo CSRF do Rails thực hiện. Đối với điều này, hãy mở application_controller.rb trong ứng dụng / bộ điều khiển và thay đổi nội dung của nó thành như sau:

class ApplicationController < ActionController::Base
  protect_from_forgery with: :null_session
end

Kiểm tra

Đó là nó! Có vẻ hơi phức tạp vì quá trình thiết lập yêu cầu nhiều tùy chỉnh, nhưng kết quả là xứng đáng.

Để kiểm tra, hãy lưu mọi thứ và khởi động máy chủ bằng cách phát hành rails s lệnh.

Sau đó, vào trình duyệt web của bạn và gõ địa chỉ https:// localhost:3000 / users. Hãy tiếp tục và thử với ứng dụng web CRUD.

Kết luận

Đó là một chặng đường dài để có được CRUD này và hoạt động. Sau lần dùng thử đầu tiên, bạn sẽ thấy rằng mọi thứ trở nên dễ dàng hơn cho các dự án trong tương lai của bạn. Tôi hy vọng dự án này sẽ giúp thiết lập một điểm khởi đầu cho những người trong số các bạn muốn bắt đầu một dự án nhanh chóng bằng cách kết hợp cả hai công nghệ.

Mặc dù chúng tôi không có dự án giàn giáo mã nguồn mở để trợ giúp nó, nhưng chúng tôi dựa vào nỗ lực của nhau để có những tài liệu như vậy. Bây giờ đến lượt của bạn; fork dự án (hoặc tạo nó từ đầu) và bắt đầu thực hiện các tùy chỉnh của bạn.

Bạn có thể tìm thấy kho lưu trữ GitHub cho ví dụ này tại đây. Chúc bạn vui vẻ!