Як оголосити клас моделі в моєму компоненті Angular 2 за допомогою TypeScript?


83

Я не новачок у 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) {}
}

Відповіді:


154

Я спробував би це:

Розділіть свою модель на окремий файл, який називається 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), я отримую помилку із повідомленням No Provider. Однак, якщо я визначу це як приватну модель: Model = new Model (), це працює. Чому це?
Скотті

7
Я не архітектор Angular 2, але виходячи зі свого досвіду роботи з Angular, коли ви вводите щось через конструктор, ви натякаєте, що воно вводиться. Ін'єкційне вимагає , щоб додати його в @Component в якості постачальника , як , наприклад: providers: [Model]. Також згідно з демонстрацією Angular 2 Tour of Hero вам слід просто використовувати її як властивість, а не для ін’єкцій, оскільки ця функціональність зазвичай зарезервована для більш складних класів, таких як послуги.
Brendon Colburn

1
Проблема з вашим способом створення моделі (не використовується new). Хіба що конструктор моделі не буде викликаний. І це instanceOf Modelбуде неправдою
Поуль Кройт

Але конструктора для початку не було? Я не бачу в цьому великої проблеми для цього впровадження. Якщо справа стає більш складною, тоді точно. Я все ще теж навчаюся. Я щойно вивчив цей стенографічний метод, яким не користувався newднями, і він подобається для простих випадків, як цей.
Brendon Colburn

5
Якщо ви використовуєте, angular-cliви можете зателефонувати, ng g class modelі він згенерує його для вас. modelзамінюється будь-яким іменем, яке ви бажаєте.
Pat Migliaccio

16

Проблема полягає в тому, що ви не додали 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() {}
}

1
Модель - це просто клас, імпорт повинен працювати в ідеалі. навіщо нам це потрібно в providersмасиві?
Pankaj Parkar

Так, але його шаблон не працював би тут, це був би model.param1. Крім того, він не надав йому початкове значення?
Brendon Colburn

@PankajParkar Оскільки я все ще отримую, No Provider for Modelякщо не додаю його до масиву провайдерів
Poul Kruijt

@PierreDuc у вас exportперед уроком Model?
Панкадж Паркар


6

У вашому випадку у вас є модель на одній сторінці, але вона оголошена після вашого класу Component, так що це вам потрібно використовувати forwardRefдля посилання Class. Не волійте робити це, завжди майте modelоб'єкт в окремому файлі.

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

Крім того, вам доведеться змінити інтерполяцію вигляду для посилання на правильний об'єкт

{{model?.param1}}

Краще, що ви повинні зробити, це те, що ви можете Modelвизначити свій клас у іншому файлі, а потім імпортувати його як час, коли вам це потрібно. Також exportперед введенням класу вкажіть ім’я, щоб ви могли імпортувати його.

import { Model } from './model';

@BrendonColburn дякую людині, я це бачив у вашій відповіді. так що я подумав , що немає сенсу редагувати моя відповідь aftewards, спасибі людини за голови, хоча, ура :)
Панкай Parkar

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

Ви можете використовувати 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
    }
}

Клас, який по суті є просто структурою / моделлю, не слід вводити, оскільки це означає, що ви можете мати лише один спільний екземпляр цього класу в межах тієї області, яку він надав. У цьому випадку це означає, що інжектор залежностей створює один екземпляр Model кожного разу, коли створюється екземпляр testWidget. Якби це було надано на рівні модуля, ви мали б лише один екземпляр, спільно використовуваний між усіма компонентами та службами цього модуля.

Натомість вам слід дотримуватися стандартних об’єктно-орієнтованих практик і створювати змінну приватної моделі як частину класу, і якщо вам потрібно передати інформацію в цю модель під час створення екземпляра екземпляра, це має обробляти служба (ін’єкційна), що надається батьківський модуль. Саме так передбачається виконувати як введення залежностей, так і зв'язок у кутовому режимі.

Крім того, як і деякі інші згадані, вам слід оголосити свої класи моделі в окремому файлі та імпортувати клас.

Я настійно рекомендую повернутися до посилання на документацію про кутові та переглянути основні сторінки різних анотацій та типів класів: https://angular.io/guide/architecture

Вам слід звернути особливу увагу на розділи про Модулі, Компоненти та Послуги / Інжекція залежностей, оскільки вони є важливими для розуміння того, як використовувати Angular на архітектурному рівні. Angular - це дуже важка мова архітектури, оскільки вона настільки високого рівня. Поділ проблем, фабрики інжекцій залежностей та версії javascript для порівнянності браузера в основному обробляються для вас, але ви повинні правильно використовувати архітектуру їх програм, інакше ви виявите, що речі не працюють, як ви очікуєте.


0

створіть model.ts у каталозі компонентів, як показано нижче

export module DataModel {
       export interface DataObjectName {
         propertyName: type;
        }
       export interface DataObjectAnother {
         propertyName: type;
        }
    }

потім у компоненті імпорту вище, як, імпортуйте {DataModel} з './model';

export class YourComponent {
   public DataObject: DataModel.DataObjectName;
}

ваш DataObject повинен мати усі властивості з DataObjectName.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.