web-dev-qa-db-ja.com

モデルクラスを宣言するにはどうすればよいですか Angular TypeScriptを使った2つのコンポーネント?

私は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のすべてのパラメータを解決できない(?)。

モデルはまだ定義されていません。それを一番上に移動します。

今を除いて私は例外が出ます:

当初の例外:モデルのプロバイダはありません!

どうやってこれを達成できますか?

編集:答えてくれてありがとう。それは私を正しい道へと導いた。

これをコンストラクタに注入するために、コンポーネントのプロバイダに追加する必要があります。

これはうまくいくようです:

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

私はこれを試してみたい:

モデルを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を呼ぶことができます、そして、それはあなたのためにそれを生成します。モデルはあなたが望むどんな名前でも置き換えられます。

119
Brendon Colburn

問題は、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) {}
}

そして、ModelComponentより上に定義する必要があります。しかし、それを自分のファイルに入れるほうがよいでしょう。

しかし、それを単なるクラスにして、そこから複数のインスタンスを作成できるようにしたい場合は、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() {}
}
14
PierreDuc

あなたのケースでは、あなたは同じページのモデルを持っています、しかしあなたはそれをあなたのComponentクラスの後に宣言しています、それであなたはforwardRefを参照するためにClassを使う必要があります。 これをしたくない、常にmodelオブジェクトを別のファイルに入れてください。

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

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

{{model?.param1}}

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

import { Model } from './model';
5
Pankaj Parkar

私のコードは

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

@ brendon's answerのコメントが提案するように、角度クリップを使用することができます。

あなたも試してみたいかもしれません:

ng g class modelsDirectoy/modelName --type=model

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

覚えておいてください: ng g class !== ng g c
しかし、angle-cliのバージョンによってはng g clをショートカットとして使うことができます。

1
xyz
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));
0
Mike Hawes

私はこれがやや古い質問であることを認識しています、しかし私はあなたがあなたのテストウィジェットクラスにモデル変数を間違って追加したことを指摘したかっただけです。 Model変数が必要な場合は、コンポーネントコンストラクターを介して渡してはいけません。あなたはサービスや他の種類の注射剤をそのように渡すことだけを意図しています。テストウィジェットを別のコンポーネント内にインスタンス化しており、モデルオブジェクトをasとして渡す必要がある場合は、AngularコアのOnInitおよびInput/Outputデザインパターンを使用することをお勧めします。

例として、あなたのコードは本当にこのようなものになるはずです。

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
user2904660