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

时间:2016-07-15 14:38:45

标签: class typescript angular

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

我没有使用简单的JavaScript模型({}),而是尝试创建一个TypeScript类。

然而,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收到错误:

  

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

所以我想,Model还没有定义......我会把它移到顶端!

除了现在我得到例外:

  

原始例外:没有Model的提供者!

我如何完成这个?

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

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

这似乎有效:

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) {}
}

8 个答案:

答案 0 :(得分:123)

我试试这个:

将您的模型拆分为一个名为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,它会为您生成。模型被你想要的任何命名所取代。

答案 1 :(得分:14)

问题在于,您尚未将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) {}
}

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

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

答案 2 :(得分:5)

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

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

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

{{model?.param1}}

您应该做的更好的事情是,您可以将Model班级定义在不同的文件和版本中。然后在需要时将其导入。在您的班级名称之前也有export,以便您可以导入它。

import { Model } from './model';

答案 3 :(得分:4)

我的代码是

    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>

答案 4 :(得分:1)

你可以使用angular-cli作为@ brendon答案中的评论。

您可能还想尝试:

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 :(得分:0)

我意识到这是一个有点老问题,但我只是想指出你已经错误地将模型变量添加到测试窗口小部件类中。如果您需要Model变量,则不应该尝试通过组件构造函数传递它。您只是想以这种方式传递服务或其他类型的注射剂。如果要在另一个组件中实例化测试窗口小部件并需要传递模型对象,我建议使用角度核心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实例。如果它是在模块级别提供的,那么您将只在该模块中的所有组件和服务之间共享一个实例。

相反,您应该遵循标准的面向对象实践并创建私有模型变量作为类的一部分,如果您需要在实例化实例时将信息传递到该模型,那么应由服务处理(可注入) )由父模块提供。这就是如何以角度执行依赖注入和通信。

此外,正如其他一些提到的那样,您应该在单独的文件中声明您的模型类并导入该类。

我强烈建议您回到角度文档参考并查看各种注释和类类型的基础知识页面: https://angular.io/guide/architecture

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

在组件目录中创建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中的所有属性。