如何使用 TypeScript 在我的 Angular 2 组件中声明模型类?

Posted

技术标签:

【中文标题】如何使用 TypeScript 在我的 Angular 2 组件中声明模型类?【英文标题】:How do I declare a model class in my Angular 2 component using TypeScript? 【发布时间】:2016-11-18 19:51:21 【问题描述】:

我是 Angular 2 和 TypeScript 的新手,我正在努力遵循最佳实践。

我尝试创建一个 TypeScript 类,而不是使用简单的 javascript 模型 ( )。

但是,Angular 2 似乎并不喜欢它。

我的代码是:

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;

我将其用作:

import  testWidget from "lib/testWidget";

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

我收到来自 Angular 的错误:

例外:无法解析 testWidget 的所有参数:(?)。

所以我想,模型还没有定义……我会把它移到顶部!

除了现在我得到了异常:

原始异常:模型没有提供者!

我该如何做到这一点??

编辑:感谢大家的回答。它让我走上了正确的道路。

为了将它注入到构造函数中,我需要将它添加到组件上的提供者中。

这似乎有效:

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) 

【问题讨论】:

【参考方案1】:

在你的组件目录中创建model.ts,如下所示

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

然后在您上面的组件导入中, 从'./model'导入DataModel;

export class YourComponent 
   public DataObject: DataModel.DataObjectName;

您的 DataObject 应该具有 DataObjectName 的所有属性。

【讨论】:

【参考方案2】:
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();
      
  

||对于非常复杂的数据对象到不存在的默认数据,可以变得非常有用。

。 .

在您的 component.ts 或 service.ts 文件中,您可以将响应数据反序列化到模型中:

// 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));

【讨论】:

【参考方案3】:

我意识到这是一个较老的问题,但我只是想指出您错误地将模型变量添加到您的测试小部件类中。如果您需要模型变量,则不应尝试通过组件构造函数将其传递。您只打算以这种方式传递服务或其他类型的注射剂。如果您在另一个组件中实例化您的测试小部件并需要传递模型对象,我建议您使用角度核心 OnInit 和输入/输出设计模式。

例如,您的代码应该看起来像这样:

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
    

不应注入本质上只是结构/模型的类,因为这意味着您只能在提供的范围内拥有该类的单个共享实例。在这种情况下,这意味着每次实例化 testWidget 时,依赖注入器都会创建一个 Model 实例。如果它是在模块级别提供的,那么您将只有一个实例在该模块内的所有组件和服务之间共享。

相反,您应该遵循标准的面向对象实践并创建一个私有模型变量作为类的一部分,并且如果您在实例化实例时需要将信息传递到该模型中,则应由服务(可注入) 由父模块提供。这就是依赖注入和通信都打算在 Angular 中执行的方式。

另外,正如其他人提到的,您应该在单独的文件中声明您的模型类并导入该类。

我强烈建议您返回 Angular 文档参考并查看有关各种注释和类类型的基础页面: https://angular.io/guide/architecture

您应该特别注意关于模块、组件和服务/依赖注入的部分,因为这些对于理解如何在架构级别上使用 Angular 至关重要。 Angular 是一种非常重架构的语言,因为它的级别非常高。关注点分离、依赖注入工厂和用于浏览器可比性的 javascript 版本控制主要是为您处理,但您必须正确使用它们的应用程序架构,否则您会发现事情无法按预期工作。

【讨论】:

【参考方案4】:

您可以使用 angular-cli 作为@brendon 回答中的 cmets 建议。

您可能还想尝试:

ng g class modelsDirectoy/modelName --type=model

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

记住: ng g class !== ng g c 但是,您可以使用 ng g cl 作为快捷方式,具体取决于您的 angular-cli 版本。

【讨论】:

【参考方案5】:

我会试试这个:

将您的模型拆分为一个名为 model.ts 的单独文件:

export class Model 
    param1: string;

将其导入您的组件。这将为您提供能够在其他组件中使用它的额外好处:

Import  Model  from './model';

在组件中初始化:

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

html 中适当地访问它:

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

我想在答案中添加@PatMigliaccio 的评论,因为适应最新的工具和技术很重要:

如果您使用angular-cli,您可以致电ng g class model,它会为您生成。模型被替换为您想要的任何名称。

【讨论】:

有趣...如果我尝试使用构造函数的简写(私有模型:模型),我会收到错误消息说没有提供者。但是,如果我将其定义为私有模型:Model = new Model(),它就可以工作。这是为什么呢? 我不是 Angular 2 架构师,但根据我对 Angular 的经验,当您通过构造函数引入某些内容时,您暗示它已被注入。注入要求您将其作为提供者添加到@Component,例如:providers: [Model]。此外,根据 Angular 2 Tour of Hero 的演示,您应该将其作为属性而不是可注入的,因为该功能通常保留给更复杂的类,例如服务。 您的模型实例化方式有问题(不使用new)。是不是模型的构造函数不会被调用。而instanceOf Model 将是错误的 但是一开始就没有构造函数?对于这个实现,我认为这不是什么大问题。如果事情变得更复杂,那么肯定。不过我也在学习。前几天我刚学会了这个不使用new的速记方法,喜欢这种简单的情况。 如果您使用angular-cli,您可以致电ng g class model,它会为您生成。 model 被替换为您想要的任何名称。【参考方案6】:

我的代码是

    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 = "";
      
  

html 是这样的:

<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>

【讨论】:

【参考方案7】:

在您的情况下,您在同一页面上有模型,但是您在 Component 类之后声明了它,因此您需要使用 forwardRef 来引用 Class不喜欢这样做,始终将model 对象放在单独的文件中。

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

此外,您必须更改视图插值以引用正确的对象

model?.param1

您应该做的更好的事情是,您可以在不同的文件中定义您的 Model 类,然后在需要时将其导入。在你的类名前还有export,这样你就可以导入它。

import  Model  from './model';

【讨论】:

@BrendonColburn 谢谢伙计,我在你的回答中看到了这一点。所以我认为事后编辑我的答案是没有意义的,不过还是谢谢你的提醒,干杯:)【参考方案8】:

问题在于您没有将Model 添加到bootstrap(这将使其成为单例)或组件定义的providers 数组中:

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

export class testWidget 
    constructor(private model: Model) 

是的,您应该在Component 之上定义Model。但最好是放在他自己的文件中。

但如果您希望它只是一个可以从中创建多个实例的类,则最好使用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() 

【讨论】:

模型只是一个类,导入应该可以正常工作。为什么我们在providers 数组中需要它? 是的,但他的模板在这里不起作用,它将是 model.param1。还有,他没有给它一个初始值? @PankajParkar 因为如果我不将No Provider for Model 添加到提供程序数组中,我仍然会得到一个No Provider for Model @PierreDuc 在Model 类之前有export 吗? @PankajParkar look here

以上是关于如何使用 TypeScript 在我的 Angular 2 组件中声明模型类?的主要内容,如果未能解决你的问题,请参考以下文章

如何在我的 auth.tsx 文件上使用 typescript 文件

如何在我的 Vuejs 项目中迁移 aws-amplify 以使用 Typescript?

如何让 child_process.spawn 在我的 TypeScript 模块中返回一个 Promise?

“如何在我的项目中匹配 typescript 版本,因为它显示错误“需要 typescript@>=2.7.0 <2.8.0”

将 Typescript 2.3 模块发布到 NPM 以供 Angular 4 使用

如何在控制器之前加载.run