Làm cách nào để khai báo một lớp mô hình trong thành phần Angular 2 của tôi bằng TypeScript?


82

Tôi mới sử dụng Angular 2 và TypeScript và tôi đang cố gắng làm theo các phương pháp hay nhất.

Thay vì sử dụng một mô hình JavaScript đơn giản ({}), tôi đang cố gắng tạo một lớp TypeScript.

Tuy nhiên, Angular 2 có vẻ không thích điều đó.

Mã của tôi là:

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

@Component({
    selector: "testWidget",
    template: "<div>This is a test and {{model.param1}} is my param.</div>"
})

export class testWidget {
    constructor(private model: Model) {}
}

class Model {
    param1: string;
}

và tôi đang sử dụng nó như:

import { testWidget} from "lib/testWidget";

@Component({
    selector: "myComponent",
    template: "<testWidget></testWidget>",
    directives: [testWidget]
})

Tôi gặp lỗi từ Angular:

NGOẠI LỆ: Không thể giải quyết tất cả các tham số cho testWidget: (?).

Vì vậy, tôi nghĩ, Mô hình vẫn chưa được xác định ... Tôi sẽ chuyển nó lên đầu!

Ngoại trừ bây giờ tôi nhận được ngoại lệ:

NGOẠI LỆ GỐC: Không có nhà cung cấp cho Model!

Làm thế nào để tôi hoàn thành điều này ??

Chỉnh sửa: Cảm ơn tất cả cho câu trả lời. Nó đã dẫn tôi đến con đường đúng đắn.

Để đưa nó vào hàm tạo, tôi cần thêm nó vào các nhà cung cấp trên thành phần.

Điều này dường như hoạt động:

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

class Model {
    param1: string;
}

@Component({
    selector: "testWidget",
    template: "<div>This is a test and {{model.param1}} is my param.</div>",
    providers: [Model]
})

export class testWidget {
    constructor(private model: Model) {}
}

Câu trả lời:


152

Tôi sẽ thử điều này:

Chia Mô hình của bạn thành một tệp riêng biệt có tên model.ts:

export class Model {
    param1: string;
}

Nhập nó vào thành phần của bạn. Điều này sẽ mang lại cho bạn lợi ích bổ sung khi có thể sử dụng nó trong các thành phần khác:

Import { Model } from './model';

Khởi tạo trong thành phần:

export class testWidget {
   public model: Model;
   constructor(){
       this.model = new Model();
       this.model.param1 = "your string value here";
   }
}

Truy cập nó một cách thích hợp trong html:

@Component({
      selector: "testWidget",
      template: "<div>This is a test and {{model.param1}} is my param.</div>"
})

Tôi muốn thêm vào câu trả lời một nhận xét của @PatMigliaccio vì điều quan trọng là phải thích ứng với các công cụ và công nghệ mới nhất:

Nếu bạn đang sử dụng, angular-clibạn có thể gọi ng g class modelvà nó sẽ tạo ra nó cho bạn. mô hình được thay thế bằng bất kỳ tên nào bạn muốn.


1
Thật thú vị ... Nếu tôi thử và thực hiện viết tắt của hàm tạo (mô hình riêng: Model), tôi gặp lỗi nói Không có nhà cung cấp. Tuy nhiên, nếu tôi định nghĩa nó là mô hình riêng: Model = new Model (), nó hoạt động. Tại sao thế này?
Scottie

7
Tôi không phải là kiến ​​trúc sư Angular 2, nhưng dựa trên kinh nghiệm của tôi với Angular khi bạn đưa một thứ gì đó vào thông qua phương thức khởi tạo mà bạn ám chỉ rằng nó sẽ được đưa vào. Tiêm đòi hỏi bạn phải thêm nó vào @Component như một nhà cung cấp như ví dụ: providers: [Model]. Cũng theo bản demo của Angular 2 Tour of Hero, bạn chỉ nên sử dụng nó dưới dạng thuộc tính thay vì có thể tiêm vì chức năng đó thường được dành cho các lớp phức tạp hơn như dịch vụ.
Brendon Colburn vào

1
Vấn đề với cách khởi tạo mô hình của bạn (không sử dụng new). Đó có phải là contructor của mô hình sẽ không được gọi. Và đó instanceOf Modelsẽ là sai lầm
Poul Kruijt

Nhưng không có hàm tạo nào để bắt đầu? Tôi không thấy điều này là một vấn đề cho việc triển khai này. Nếu mọi thứ trở nên phức tạp hơn thì chắc chắn. Tôi vẫn đang học. Hôm trước mình mới học được phương pháp tốc ký này không dùng newvà thích nó cho những trường hợp đơn giản như thế này.
Brendon Colburn

5
Nếu bạn đang sử dụng, angular-clibạn có thể gọi ng g class modelvà nó sẽ tạo ra nó cho bạn. modelđược thay thế bằng bất kỳ tên nào bạn muốn.
Pat Migliaccio

16

Vấn đề dối trá mà bạn chưa thêm Modelcho một trong hai bootstrap(mà sẽ làm cho nó một singleton), hoặc các providersmảng của định nghĩa thành phần của bạn:

@Component({
    selector: "testWidget",
    template: "<div>This is a test and {{param1}} is my param.</div>",
    providers : [
       Model
    ]
})

export class testWidget {
    constructor(private model: Model) {}
}

Và có, bạn nên xác định Modelở trên Component. Nhưng tốt hơn là nên đưa nó vào hồ sơ của riêng anh ấy.

Nhưng nếu bạn muốn nó chỉ là một lớp mà từ đó bạn có thể tạo nhiều phiên bản, tốt hơn bạn nên sử dụng new.

@Component({
    selector: "testWidget",
    template: "<div>This is a test and {{param1}} is my param.</div>"
})

export class testWidget {

    private model: Model = new Model();

    constructor() {}
}

1
Mô hình chỉ là một lớp, nhập nên hoạt động lý tưởng. tại sao chúng ta cần nó trong providersmảng?
Pankaj Parkar

Vâng, nhưng cách tạo mẫu của anh ấy sẽ không hoạt động ở đây, nó sẽ là model.param1. Ngoài ra, anh ấy đã không cho nó một giá trị ban đầu?
Brendon Colburn

@PankajParkar Bởi vì tôi vẫn nhận được một No Provider for Modelnếu tôi không thêm nó vào mảng cung cấp dịch vụ
Poul Kruijt

@PierreDuc bạn có exporttrước Modellớp không?
Pankaj Parkar

@PankajParkar nhìn đây
Poul Kruijt

6

Trong trường hợp của bạn, bạn đang có mô hình trên cùng một trang, nhưng bạn đã khai báo nó sau lớp Thành phần của mình, vì vậy bạn cần sử dụng forwardRefđể tham khảo Class. Không thích làm điều này, luôn luôn có modelđối tượng trong tệp riêng biệt.

export class testWidget {
    constructor(@Inject(forwardRef(() => Model)) private service: Model) {}
}

Ngoài ra, bạn phải thay đổi bạn xem nội suy để tham chiếu đến đối tượng chính xác

{{model?.param1}}

Điều tốt hơn bạn nên làm là, bạn có thể Modelxác định Lớp của mình trong tệp khác và sau đó nhập nó dưới dạng tệp khi bạn yêu cầu. Cũng có exporttrước tên lớp của bạn, để bạn có thể nhập nó.

import { Model } from './model';

@BrendonColburn cảm ơn bạn, tôi đã thấy điều đó trong câu trả lời của bạn. vì vậy tôi nghĩ không có ý nghĩa để chỉnh sửa aftewards câu trả lời của tôi, Cảm ơn người đàn ông cho người đứng đầu lên mặc dù, cheers :)
Pankaj Parkar

5

mã của tôi là

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

class model {
  username : string;
  password : string;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})



export class AppComponent {

 username : string;
 password : string;
  usermodel = new model();

  login(){
  if(this.usermodel.username == "admin"){
    alert("hi");
  }else{
    alert("bye");
    this.usermodel.username = "";
  }    
  }
}

và html sẽ như thế này:

<div class="login">
  Usernmae : <input type="text" [(ngModel)]="usermodel.username"/>
  Password : <input type="text" [(ngModel)]="usermodel.password"/>
  <input type="button" value="Click Me" (click)="login()" />
</div>

3
export class Car {
  id: number;
  make: string;
  model: string;
  color: string;
  year: Date;

  constructor(car) {
      {
        this.id = car.id;
        this.make = car.make || '';
        this.model = car.model || '';
        this.color = car.color || '';
        this.year = new Date(car.year).getYear();
      }
  }
}

Cái || có thể trở nên siêu hữu ích cho các đối tượng dữ liệu rất phức tạp đến dữ liệu mặc định không tồn tại.

. .

Trong tệp component.ts hoặc service.ts của bạn, bạn có thể giải mã dữ liệu phản hồi vào mô hình:

// Import the car model
import { Car } from './car.model.ts';

// If single object
car = new Car(someObject);

// If array of cars
cars = someDataToDeserialize.map(c => new Car(c));

2

Bạn có thể sử dụng angle-cli như các nhận xét trong câu trả lời của @ brendon gợi ý.

Bạn cũng có thể muốn thử:

ng g class modelsDirectoy/modelName --type=model

/* will create
 src/app/modelsDirectoy
 ├── modelName.model.ts
 ├── ...
 ...
*/

Lưu ý ng g class :! == ng g c
Tuy nhiên, bạn có thể sử dụng ng g cllàm phím tắt tùy thuộc vào phiên bản angle-cli của bạn.


0

Tôi nhận thấy đây là một câu hỏi hơi cũ hơn, nhưng tôi chỉ muốn chỉ ra rằng bạn đã thêm biến mô hình vào lớp widget thử nghiệm của mình không chính xác. Nếu bạn cần một biến Model, bạn không nên cố gắng chuyển nó qua hàm tạo thành phần. Bạn chỉ có ý định chuyển các dịch vụ hoặc các loại vật liệu tiêm khác theo cách đó. Nếu bạn đang khởi tạo tiện ích con thử nghiệm của mình bên trong một thành phần khác và cần chuyển một đối tượng mô hình như, tôi khuyên bạn nên sử dụng các mẫu thiết kế OnInit và Input / Output lõi góc cạnh.

Ví dụ, mã của bạn thực sự sẽ trông giống như sau:

import { Component, Input, OnInit } from "@angular/core";
import { YourModelLoadingService } from "../yourModuleRootFolderPath/index"

class Model {
    param1: string;
}

@Component({
    selector: "testWidget",
    template: "<div>This is a test and {{model.param1}} is my param.</div>",
    providers: [ YourModelLoadingService ]
})

export class testWidget implements OnInit {
    @Input() model: Model; //Use this if you want the parent component instantiating this
        //one to be able to directly set the model's value
    private _model: Model; //Use this if you only want the model to be private within
        //the component along with a service to load the model's value
    constructor(
        private _yourModelLoadingService: YourModelLoadingService //This service should
        //usually be provided at the module level, not the component level
    ) {}

    ngOnInit() {
        this.load();
    }

    private load() {
        //add some code to make your component read only,
        //possibly add a busy spinner on top of your view
        //This is to avoid bugs as well as communicate to the user what's
        //actually going on

        //If using the Input model so the parent scope can set the contents of model,
        //add code an event call back for when model gets set via the parent
        //On event: now that loading is done, disable read only mode and your spinner
        //if you added one

        //If using the service to set the contents of model, add code that calls your
        //service's functions that return the value of model
        //After setting the value of model, disable read only mode and your spinner
        //if you added one. Depending on if you leverage Observables, or other methods
        //this may also be done in a callback
    }
}

Không nên đưa vào một lớp về cơ bản chỉ là một cấu trúc / mô hình, vì nó có nghĩa là bạn chỉ có thể có một phiên bản chia sẻ duy nhất của lớp đó trong phạm vi mà nó được cung cấp. Trong trường hợp này, điều đó có nghĩa là một phiên bản Model duy nhất được tạo bởi bộ phun phụ thuộc mỗi khi testWidget được khởi tạo. Nếu nó được cung cấp ở cấp mô-đun, bạn sẽ chỉ có một phiên bản duy nhất được chia sẻ giữa tất cả các thành phần và dịch vụ trong mô-đun đó.

Thay vào đó, bạn nên tuân theo các thực hành Hướng đối tượng tiêu chuẩn và tạo một biến mô hình riêng như một phần của lớp và nếu bạn cần chuyển thông tin vào mô hình đó khi bạn khởi tạo phiên bản, thì thông tin đó sẽ được xử lý bởi một dịch vụ (có thể đưa vào) được cung cấp bởi mô-đun mẹ. Đây là cách mà cả quá trình tiêm phụ thuộc và giao tiếp đều được dự định thực hiện theo góc độ.

Ngoài ra, như một số người khác đã đề cập, bạn nên khai báo các lớp mô hình của mình trong một tệp riêng biệt và nhập lớp đó.

Tôi thực sự khuyên bạn nên quay lại tài liệu tham khảo góc cạnh và xem lại các trang thông tin cơ bản về các chú thích và loại lớp khác nhau: https://angular.io/guide/architecture

Bạn nên đặc biệt chú ý đến các phần về Mô-đun, Thành phần và Dịch vụ / Truyền phụ thuộc vì đây là những điều cần thiết để hiểu cách sử dụng Angular ở cấp độ kiến ​​trúc. Angular là một ngôn ngữ rất nặng về kiến ​​trúc vì nó rất cao cấp. Tách các mối quan tâm, các nhà máy chèn phụ thuộc và lập phiên bản javascript để so sánh trình duyệt chủ yếu được xử lý cho bạn, nhưng bạn phải sử dụng kiến ​​trúc ứng dụng của chúng một cách chính xác nếu không bạn sẽ thấy mọi thứ không hoạt động như bạn mong đợi.


0

tạo model.ts trong thư mục thành phần của bạn như bên dưới

export module DataModel {
       export interface DataObjectName {
         propertyName: type;
        }
       export interface DataObjectAnother {
         propertyName: type;
        }
    }

thì trong phần nhập thành phần của bạn ở trên dưới dạng, hãy nhập {DataModel} từ './model';

export class YourComponent {
   public DataObject: DataModel.DataObjectName;
}

DataObject của bạn phải có tất cả các thuộc tính từ DataObjectName.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.