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


82

我是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的错误消息:

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

所以我想,尚未定义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) {}
}

Answers:


152

我会尝试这样的:

将模型拆分为一个单独的文件,称为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
有趣的...如果我尝试执行构造函数的简化形式(私有模型:Model),则会收到错误消息“无提供程序”。但是,如果我将其定义为私有模型:Model = new Model(),它将起作用。为什么是这样?
斯科蒂(Scottie)2016年

7
我不是Angular 2架构师,但是基于我对Angular的经验,当您通过构造函数引入某些东西时,就意味着它已被注入。注入要求您将其作为提供程序添加到@Component,例如:providers: [Model]。同样,按照Angular 2 Tour of Hero的演示,您应该只将其作为属性而不是可注入的,因为该功能通常是为更复杂的类(例如服务)保留的。
布伦登·科尔本

1
您实例化模型的方式存在问题(不使用new)。是模型的构造函数不会被调用。那instanceOf Model将是错误的
Poul Kruijt

但是没有开始的构造函数吗?对于该实现,我认为这并不是什么大问题。如果事情变得更加复杂,那么可以肯定。我仍然在学习。我刚刚学会了不使用new前一天的速记方法,并且喜欢这种简单情况。
布伦登·科尔本

5
如果您正在使用angular-cli,则可以致电ng g class model,它将为您生成。model被您想要的任何命名所取代。
Pat Migliaccio

16

问题在于您尚未添加 Modelbootstrap(将使它成为单例)或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() {}
}

1
模型只是一类,导入应该可以理想地工作。为什么我们需要providers数组?
Pankaj Parkar '16

是的,但是他的模板在这里不起作用,它将是model.param1。另外,他没有给它一个初始值吗?
布伦登·科尔本

@PankajParkar因为我还得到一个No Provider for Model,如果我不把它添加到阵列供应商
波尔Kruijt

@PierreDuc上课export前有Model吗?
Pankaj Parkar

@PankajParkar看这里
波尔Kruijt

6

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

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

另外,您必须更改视图插值才能引用正确的对象

{{model?.param1}}

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

import { Model } from './model';

@BrendonColburn谢谢你,我在你的回答中看到了。所以我认为以后再没有任何意义可以编辑我的答案了,虽然谢谢大家的抬头,但还是要
加油

5

我的代码是

    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>

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

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

。。

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

2

您可以使用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版本将其用作快捷方式。


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版本控制,但是您必须正确使用它们的应用程序体系结构,否则您会发现事情无法按预期进行。


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的所有属性。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.