Comment déclarer une classe de modèle dans mon composant Angular 2 en utilisant TypeScript?

Je suis nouveau à Angular 2 et TypeScript et j'essaie de suivre les meilleures pratiques.

Au lieu d'utiliser un simple modèle JavaScript ({ }), j'essaie de créer une classe TypeScript.

Cependant, Angular 2 ne semble pas l'aimer.

Mon code est:

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

Et je l'utilise comme:

import { testWidget} from "lib/testWidget";

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

Je reçois une erreur de Angular:

EXCEPTION: Impossible de résoudre tous les paramètres de testWidget: (?).

Donc j'ai pensé, le modèle n'est pas défini encore... Je vais le déplacer vers le haut!

Sauf que maintenant je reçois l'exception:

EXCEPTION originale: aucun fournisseur pour le modèle!

Comment puis-je accomplir cela??

Edit: merci à tous pour la réponse. Il m'a conduit dans le droit chemin.

Pour l'injecter dans le constructeur, je dois l'Ajouter aux fournisseurs du composant.

Cela semble fonctionner:

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) {}
}
47
demandé sur Scottie 2016-07-15 17:38:45

6 réponses

Je voudrais essayer ceci:

Divisez votre modèle en un fichier séparé appelé model.ts:

export class Model {
    param1: string;
}

Importez - le dans votre composant. Cela vous donnera l'avantage supplémentaire de pouvoir l'utiliser dans d'autres composants:

Import { Model } from './model';

Initialiser dans le composant:

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

Accédez-y de manière appropriée dans le html:

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

Je veux ajouter à la réponse un commentaire fait par @PatMigliaccio car il est important de s'adapter aux derniers outils et technologies:

Si vous utilisez angular-cli, vous pouvez appeler ng g class model et il va générer pour vous. modèle remplacé par tout ce que vous désirez nommer.

89
répondu Brendon Colburn 2018-02-07 18:52:46

Le problème réside dans le fait que vous n'avez pas ajouté Model à bootstrap (ce qui en fera un singleton), ou au tableau providers de votre définition de Composant:

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

export class testWidget {
    constructor(private model: Model) {}
}

Et oui, vous devez définir Model au-dessus de la Component. Mais mieux serait de le mettre dans son propre dossier.

Mais si vous voulez que ce soit juste une classe à partir de laquelle vous pouvez créer plusieurs instances, il vaut mieux utiliser 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() {}
}
11
répondu PierreDuc 2016-07-15 15:01:24

Dans votre cas, vous avez un modèle sur la même page, mais vous l'avez déclaré après votre classe de Composant, donc vous devez utiliser forwardRef pour faire référence à Class. ne préférez pas faire cela, ayez toujours model objet dans un fichier séparé.

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

En outre, vous devez modifier votre interpolation de vue pour faire référence à l'objet correct

{{model?.param1}}

La meilleure chose que vous devriez faire est, vous pouvez avoir votre classe Model définir dans un fichier différent et ensuite l'importer en tant que lorsque vous en avez besoin par faire. Ayez également export avant votre nom de classe, afin que vous puissiez l'importer.

import { Model } from './model';
5
répondu Pankaj Parkar 2016-07-15 15:02:47

Mon code est

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

Et le html va comme ceci:

<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
répondu Ahmed Basha 2017-01-24 02:54:47

Vous pouvez utiliser l'Angular-cli comme le suggèrent les commentaires dans la réponse de @brendon.

, Vous pouvez également essayer:

ng g class modelsDirectoy/modelName --type=model

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

Gardez à l'esprit: ng g class !== ng g c
Cependant, vous pouvez utiliser ng g cl comme raccourci en fonction de votre version angular-cli.

0
répondu xyz 2018-04-19 17:22:44

Je me rends compte que c'est une question un peu plus ancienne, mais je voulais juste souligner que vous avez incorrectement ajouté la variable de modèle à votre classe de widget de test. Si vous avez besoin d'une variable de modèle, vous ne devriez pas essayer de la transmettre via le constructeur de composants. Vous êtes uniquement destiné à passer des services ou d'autres types d'injectables de cette façon. Si vous instanciez votre widget de test à l'intérieur d'un autre composant et que vous devez passer un objet model as, je vous recommande d'utiliser le noyau angulaire OnInit et Modèles de conception d'entrée/sortie.

Par exemple, votre code devrait vraiment ressembler à ceci:

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

Une classe qui est essentiellement juste une structure / modèle ne doit pas être injectée, car cela signifie que vous ne pouvez avoir qu'un seul instancié partagé de cette classe dans la portée fournie. Dans ce cas, cela signifie qu'une seule instance de Model est créée par l'injecteur de dépendance chaque fois que testWidget est instancié. Si elle était fournie au niveau du module, vous n'auriez qu'un instance unique partagée entre tous les composants et services de ce module.

Au lieu de cela, vous devriez suivre les pratiques orientées objet standard et créer une variable de modèle privé dans le cadre de la classe, et si vous avez besoin de transmettre des informations dans ce modèle lorsque vous instanciez l'instance, cela devrait être géré par un service (injectable) fourni par le module parent. C'est ainsi que l'injection de dépendance et la communication sont destinées à être effectuées en angulaire.

Aussi, comme certains des autres mentionnés, vous devriez déclarer vos classes de modèle dans un fichier séparé et importer la classe.

Je recommande fortement de revenir à la référence de la documentation angulaire et de passer en revue les pages de base sur les différents types d'annotations et de classes: https://angular.io/guide/architecture

Vous devriez porter une attention particulière aux sections sur les Modules, Les composants et les services / injection de dépendance car ceux-ci sont essentiels pour comprendre comment utilisez angulaire au niveau architectural. Angular est un langage très lourd d'architecture car il est si haut niveau. La séparation des préoccupations, les usines d'injection de dépendance et le versionnage javascript pour la comparabilité du navigateur sont principalement gérés pour vous, mais vous devez utiliser leur architecture d'application correctement ou vous constaterez que les choses ne fonctionnent pas comme prévu.

0
répondu user2904660 2018-04-23 16:46:51