TypeScript kullanarak Angular 2 bileşenimde bir model sınıfını nasıl bildirebilirim?


82

Angular 2 ve TypeScript'te yeniyim ve en iyi uygulamaları izlemeye çalışıyorum.

Basit bir JavaScript modeli ({}) kullanmak yerine, bir TypeScript sınıfı oluşturmaya çalışıyorum.

Ancak, Angular 2 bundan hoşlanmıyor gibi görünüyor.

Benim kodum:

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

ve bunu şu şekilde kullanıyorum:

import { testWidget} from "lib/testWidget";

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

Angular'dan bir hata alıyorum:

İSTİSNA: testWidget için tüm parametreler çözülemiyor: (?).

Bu yüzden Model henüz tanımlanmadı diye düşündüm ... En üste taşıyacağım!

Şu an hariç istisnayı alıyorum:

ORİJİNAL İSTİSNA: Model için sağlayıcı yok!

Bunu nasıl başarırım?

Düzenleme: Cevap için herkese teşekkürler. Beni doğru yola götürdü.

Bunu yapıcıya enjekte etmek için, onu bileşen üzerindeki sağlayıcılara eklemem gerekiyor.

Bu işe yarıyor gibi görünüyor:

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

Yanıtlar:


153

Bunu denerdim:

Modelinizi ayrı bir dosyaya bölün model.ts:

export class Model {
    param1: string;
}

Bileşeninize aktarın. Bu size, onu diğer bileşenlerde kullanabilmenin ek faydasını sağlayacaktır:

Import { Model } from './model';

Bileşeni başlatın:

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

Buna html'de uygun şekilde erişin:

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

Cevaba @PatMigliaccio tarafından yapılan bir yorumu eklemek istiyorum çünkü en son araçlara ve teknolojilere uyum sağlamak önemlidir:

Eğer kullanıyorsanız angular-cliarayabilir ng g class modelve sizin için üretecektir. model, istediğiniz isimle değiştiriliyor.


1
İlginç ... Yapıcı kelimesinin (özel model: Model) kısaltmasını dener ve uygularsam, Sağlayıcı Yok diyen hata alıyorum. Ancak bunu özel model olarak tanımlarsam: Model = new Model (), işe yarıyor. Bu neden?
Scottie

7
Ben bir Angular 2 mimarı değilim, ancak Angular ile olan deneyimime dayanarak, yapıcı aracılığıyla bir şey getirdiğinizde, onun enjekte edildiğini ima ediyorsunuz. Enjekte Böyle böyle bir sağlayıcı olarak @Component eklemek gerekir: providers: [Model]. Ayrıca, Angular 2 Tour of Hero's demosuna göre, bu işlevsellik tipik olarak hizmetler gibi daha karmaşık sınıflar için ayrıldığından, bir enjekte edilebilir yerine bir özellik olarak gitmelisiniz.
Brendon Colburn

1
Modeli örnekleme yönteminizle ilgili sorun (kullanmama new). Modelin müteahhidi aranmayacak mı? Ve bu instanceOf Modelyanlış olacak
Poul Kruijt

Ama başlamak için kurucu yok muydu? Bu uygulama için bunu bir sorun olarak görmüyorum. İşler daha karmaşık hale gelirse emin olun. Yine de öğreniyorum. newGeçen gün kullanmamanın bu kısa yöntemini yeni öğrendim ve bunun gibi basit durumlarda hoşuma gitti.
Brendon Colburn

5
Eğer kullanıyorsanız angular-cliarayabilir ng g class modelve sizin için üretecektir. modelistediğiniz isimle değiştirilmek.
Pat Migliaccio

16

Eğer eklememiş olması sorun yatıyor Modelya bootstrap(bir tekil yapacak) ya karşı providersda bileşen tanımının dizisi:

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

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

Ve evet, tanımlamalıdır Modelyukarıda Component. Ama kendi dosyasına koymak daha iyi olur.

Ancak, birden çok örnek oluşturabileceğiniz bir sınıf olmasını istiyorsanız, kullansanız iyi olur 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
Model sadece bir sınıftır, içe aktarma ideal olarak çalışmalıdır. neden providersdiziye ihtiyacımız var ?
Pankaj Parkar

Evet ama şablonu burada işe yaramaz, model.param1 olurdu. Ayrıca, ona bir başlangıç ​​değeri vermedi mi?
Brendon Colburn

@PankajParkar hala bir olsun Çünkü No Provider for Modelben sağlayıcıları diziye eklemek yoksa
Poul Kruijt

@PierreDuc dersten exportönce var Modelmı?
Pankaj Parkar

@PankajParkar buraya bak
Poul Kruijt

6

Sizin durumunuzda modeli aynı sayfada görüyorsanız, ancak onu Bileşen sınıfınızdan sonra ilan ettiniz, bu yüzden forwardRefbaşvurmak için kullanmanız gerekir Class. Bunu yapmayı tercih etmeyin, her zaman modelayrı bir dosyada nesne bulundurun.

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

Ek olarak, doğru nesneye başvurmak için görünüm enterpolasyonunu değiştirmeniz gerekir.

{{model?.param1}}

Yapmanız gereken daha iyi şey, ModelSınıfınızın farklı bir dosyada tanımlanmasını ve ardından bunu yaparak istediğiniz zaman bir sınıf olarak içe aktarabilmenizdir. Ayrıca, exportiçeri aktarabilmeniz için sınıfınızın adını da ekleyin.

import { Model } from './model';

@BrendonColburn teşekkürler dostum, cevabında bunu gördüm. bu yüzden düzenleme için hiçbir anlam cevabım Aftewards, kafaları için teşekkürler adam :) şerefe, yukarı olsa orada düşünce
Pankaj Parkar

5

benim kodum

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

ve html şöyle olur:

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

|| çok karmaşık veri nesneleri için mevcut olmayan varsayılan verilere süper kullanışlı hale gelebilir.

. .

Component.ts veya service.ts dosyanızda, yanıt verilerinin serisini modelden kaldırabilirsiniz:

// 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'un cevabındaki yorumların önerdiği gibi açısal klibi kullanabilirsiniz.

Şunları da denemek isteyebilirsiniz:

ng g class modelsDirectoy/modelName --type=model

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

Unutmayın ng g class :! == ng g c
Ancak, ng g claçısal-cli sürümünüze bağlı olarak kısayol olarak kullanabilirsiniz .


0

Bunun biraz daha eski bir soru olduğunun farkındayım, ancak model değişkenini test widget'ı sınıfınıza yanlış eklediğinizi belirtmek istedim. Bir Model değişkenine ihtiyacınız varsa, onu bileşen yapıcısından geçirmeye çalışmamalısınız. Yalnızca hizmetleri veya diğer enjekte edilebilir türlerini bu şekilde geçirmeniz amaçlanmaktadır. Test widget'ınızı başka bir bileşenin içinde somutlaştırıyorsanız ve bir model nesnesini olarak iletmeniz gerekiyorsa, açısal çekirdek OnInit ve Input / Output tasarım modellerini kullanmanızı tavsiye ederim.

Örnek olarak, kodunuz gerçekten şöyle görünmelidir:

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

Esasen sadece bir yapı / model olan bir sınıf enjekte edilmemelidir, çünkü bu, sağlandığı kapsam dahilinde o sınıfın yalnızca tek bir paylaşılan örneğine sahip olabileceğiniz anlamına gelir. Bu durumda, testWidget her başlatıldığında bağımlılık enjektörü tarafından tek bir Model örneğinin oluşturulduğu anlamına gelir. Modül düzeyinde sağlanmış olsaydı, o modül içindeki tüm bileşenler ve hizmetler arasında yalnızca tek bir örneğiniz paylaşılırdı.

Bunun yerine, standart Nesne Yönelimli uygulamaları takip etmeli ve sınıfın bir parçası olarak özel bir model değişkeni oluşturmalısınız ve örneği başlattığınızda bu modele bilgi aktarmanız gerekiyorsa, bu, tarafından sağlanan bir hizmet (enjekte edilebilir) tarafından ele alınmalıdır. ana modül. Bu, hem bağımlılık enjeksiyonunun hem de iletişimin açısal olarak gerçekleştirilmesi amaçlanmıştır.

Ayrıca, diğer bazılarının da belirtildiği gibi, model sınıflarınızı ayrı bir dosyada beyan etmeli ve sınıfı içe aktarmalısınız.

Açısal dokümantasyon referansına geri dönmenizi ve çeşitli not ve sınıf türlerindeki temel sayfaları incelemenizi şiddetle tavsiye ederim: https://angular.io/guide/architecture

Angular'ın mimari düzeyde nasıl kullanılacağını anlamak için gerekli olan Modüller, Bileşenler ve Hizmetler / Bağımlılık Ekleme bölümlerine özellikle dikkat etmelisiniz. Angular çok mimari ağırlıklı bir dildir çünkü çok yüksek seviyededir. Endişelerin ayrılması, bağımlılık enjeksiyon fabrikaları ve tarayıcı karşılaştırılabilirliği için javascript sürümlemesi esas olarak sizin için ele alınır, ancak bunların uygulama mimarisini doğru kullanmanız gerekir, aksi takdirde şeylerin beklediğiniz gibi çalışmadığını görürsünüz.


0

aşağıdaki gibi bileşen dizininizde model.ts oluşturun

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

daha sonra yukarıdaki bileşen içe aktarmanızda, {DataModel} 'i' ./model'den içe aktarın;

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

DataObject'iniz DataObjectName'deki tüm özelliklere sahip olmalıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.