TypeScriptを使用してAngular2コンポーネントでモデルクラスを宣言するにはどうすればよいですか?


82

私はAngular2とTypeScriptを初めて使用し、ベストプラクティスに従おうとしています。

単純なJavaScriptモデル({})を使用する代わりに、TypeScriptクラスを作成しようとしています。

ただし、Angular2はそれを好まないようです。

私のコードは:

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

回答:


153

私はこれを試してみます:

モデルを次のような別のファイルに分割します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
興味深い...コンストラクター(プライベートモデル:モデル)の省略形を実行しようとすると、プロバイダーなしというエラーが表示されます。ただし、private model:Model = new Model()として定義すると、機能します。どうしてこれなの?
スコッティ2016

7
私はAngular2アーキテクトではありませんが、コンストラクターを介して何かを持ち込んだときのAngularでの経験に基づいて、それが注入されていることを示唆しています。注入するには、次のようなプロバイダーとして@Componentに追加する必要がありますproviders: [Model]。また、Angular 2 Tour of Heroのデモによると、その機能は通常、サービスなどのより複雑なクラス用に予約されているため、注入可能なものではなく、プロパティとして使用する必要があります。
Brendon Colburn 2016

1
モデルをインスタンス化する方法に問題があります(を使用しないnew)。モデルの作成者が呼び出されないということです。そしてそれinstanceOf Modelは誤りです
Poul Kruijt 2016

しかし、そもそもコンストラクターはありませんでしたか?この実装では、これはそれほど問題にはなりません。物事がより複雑になった場合は、確かに。私もまだ学んでいます。私はnew先日使用しないというこの速記法を学び、このような単純なケースでそれが好きです。
Brendon Colburn 2016

5
使用しているangular-cli場合は、電話をかけることができng g class model、それが生成されます。modelあなたが望むどんな名前にも置き換えられます。
Pat Migliaccio 2017

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 2016

ええ、でも彼のテンプレートはここでは機能しません。model.param1になります。また、彼はそれに初期値を与えていませんか?
Brendon Colburn 2016

@PankajParkarNo Provider for Modelプロバイダー配列に追加しなくても、まだ取得できるため
Poul Kruijt 2016

@PierreDucクラスのexport前にありますModelか?
Pankaj Parkar 2016


6

あなたの場合、同じページにモデルがありますが、Componentクラスの後にモデルが宣言されているため、forwardRefを参照するために使用する必要がありますClassこれを行うことを好まないでくださいmodel。常に別のファイルにオブジェクトを置いてください。

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

さらに、正しいオブジェクトを参照するには、ビューの補間を変更する必要があります

{{model?.param1}}

あなたがすべきより良いことは、あなたのModelクラスを別のファイルで定義させ、それを実行することによって必要なときにそれをインポートすることができるということです。またexport、クラス名を前に付けて、インポートできるようにします。

import { Model } from './model';

@BrendonColburnありがとう、私はあなたの答えでそれを見ました。だから私は自分の答えを後で編集する意味はないと思った、しかし頭を上げてくれてありがとう、乾杯:)
Pankaj Parkar 2016

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>

4
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

@brendonの回答のコメントが示唆するように、angular-cliを使用できます。

また、試してみることもできます。

ng g class modelsDirectoy/modelName --type=model

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

注意ng g class !== ng g c
ただし、ng g clangular-cliのバージョンによってはショートカットとして使用できます。


0

これはやや古い質問だと思いますが、モデル変数をテストウィジェットクラスに誤って追加したことを指摘したいと思います。Model変数が必要な場合は、コンポーネントコンストラクターを介して渡そうとしないでください。あなたはその方法でサービスまたは他のタイプの注射剤を渡すことだけを意図しています。別のコンポーネント内でテストウィジェットをインスタンス化していて、モデルオブジェクトをとして渡す必要がある場合は、Angularコアの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の単一インスタンスが作成されることを意味します。モジュールレベルで提供された場合、そのモジュール内のすべてのコンポーネントとサービス間で共有されるインスタンスは1つだけになります。

代わりに、標準のオブジェクト指向プラクティスに従い、クラスの一部としてプライベートモデル変数を作成する必要があります。インスタンスをインスタンス化するときにそのモデルに情報を渡す必要がある場合は、によって提供されるサービス(注入可能)によって処理される必要があります。親モジュール。これは、依存性注入と通信の両方が角度で実行されることを意図している方法です。

また、他のいくつかで述べたように、モデルクラスを別のファイルで宣言し、クラスをインポートする必要があります。

Angularのドキュメントリファレンスに戻って、さまざまなアノテーションとクラスタイプの基本ページを確認することを強くお勧めします: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のすべてのプロパティが必要です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.