Angular2 - haruskah variabel pribadi dapat diakses di templat?

143

Jika suatu variabel dideklarasikan private pada kelas komponen, apakah saya dapat mengaksesnya di templat komponen itu?

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>{{title}}</h2>
      <h2>Hello {{userName}}</h2> // I am getting this name
    </div>
  `,
})
export class App {
  public title = 'Angular 2';
  private userName = "Test Name"; //declared as private
}
3gwebrain
sumber

Jawaban:

226

Tidak, Anda tidak boleh menggunakan variabel pribadi di templat Anda.

Sementara saya suka jawaban drewmoore dan melihat logika konseptual yang sempurna di dalamnya, implementasi itu salah. Templat tidak ada di dalam kelas komponen, tetapi di luarnya. Lihatlah repo ini untuk buktinya.

Satu-satunya alasan mengapa ini berhasil adalah karena privatekata kunci TypeScript tidak benar-benar membuat anggota menjadi pribadi. Kompilasi Just-in-Time terjadi di browser saat runtime dan JS tidak memiliki konsep anggota pribadi (belum?). Penghargaan diberikan kepada Sander Elias karena menempatkan saya di jalur yang benar.

Dengan ngckompilasi Ahead-of-Time, Anda akan mendapatkan kesalahan jika Anda mencoba mengakses anggota pribadi komponen dari templat. Klo repo demonstrasi, ubah MyComponentvisibilitas anggota ke pribadi dan Anda akan mendapatkan kesalahan kompilasi, saat berjalan ngc. Berikut ini juga jawaban spesifik untuk kompilasi Ahead-of-Time.

Yaroslav Admin
sumber
6
ini adalah komentar terbaik dan imo harus menjadi jawaban yang diterima. Ini bukan berarti Anda dapat menggunakan variabel pribadi setelah ditransmisikan, bahwa Anda harus .. Menjaga kode tetap bersih!
Sam Vloeberghs
2
Ini adalah satu-satunya jawaban yang valid! Codelyzer sekarang memperingatkan Anda ketika Anda menggunakan var pribadi di templat Anda.
maxime1992
7
Satu-satunya masalah saya dengan ini adalah, bagaimana Anda membedakan antara anggota yang benar-benar terbuka untuk umum seperti @ Input dan Output ke anggota yang kami ingin hanya mengekspos ke template kami dan bukan dunia luar. Jika Anda sedang membangun komponen yang dapat digunakan kembali di mana Anda ingin metode / anggota dapat diakses oleh templat tetapi tidak untuk komponen lain. Saya pikir jawaban aslinya benar. Templat adalah bagian dari komponen.
Ashg
1
Saya setuju dengan @Ashg - dan bukan hanya Input dan Output. Bagaimana ketika saya ingin berkomunikasi antar komponen, misalnya dengan menyuntikkan komponen induk ke anaknya. Komponen child kemudian dapat melihat semua yang diekspos orangtua ke templatnya, alih-alih hanya metode yang ingin diekspos orangtua ke dunia luar. Dalam batasan Angular, jawaban ini tetap yang benar, tetapi saya tidak berpikir desain ini telah dipikirkan dengan baik.
Dan King
Ini adalah jawaban yang bagus karena membahas keterbatasan dalam kompilasi AoT Angular dan bagaimana cara mengatasinya. Namun, IMO pertanyaannya adalah konseptual (sengaja atau tidak). Secara konseptual, templat adalah bagian dari definisi kelas. Template tidak memperluas atau mewarisi kelas dan mereka tidak mengakses objek yang dipakai secara eksternal ... itu sebaliknya. Template didefinisikan dalam kelas itu sendiri sehingga, secara konseptual, mereka adalah bagian dari kelas dan secara konseptual harus memiliki akses ke anggota pribadi.
A-Diddy
85

Sunting: Jawaban ini sekarang salah. Tidak ada panduan resmi tentang topik ketika saya mempostingnya, tetapi seperti yang dijelaskan dalam jawaban @ Yaroslov (luar biasa, dan benar), ini tidak lagi menjadi masalah: Pembuat kode sekarang memperingatkan dan kompilasi AoT akan gagal pada referensi ke variabel pribadi dalam templat komponen . Yang mengatakan, pada level konseptual semuanya di sini tetap valid, jadi saya akan meninggalkan jawaban ini karena tampaknya telah membantu.


Ya, ini diharapkan.

Perlu diingat bahwa privatedan pengubah akses lainnya adalah konstruksi TypeScript, sedangkan Component / controller / template adalah konstruksi sudut yang tidak diketahui oleh apa pun tentang Typescript. Pengubah akses mengontrol visibilitas antar kelas: Membuat bidang privatetidak bisa dilakukan kelas lain dari memiliki akses ke sana, tetapi templat dan pengontrol adalah hal-hal yang ada di dalam kelas.

Secara teknis itu tidak benar, tetapi (sebagai pengganti memahami bagaimana kelas berhubungan dengan dekorator dan metadata mereka), mungkin akan membantu untuk memikirkannya dengan cara ini, karena yang penting (IMHO) adalah beralih dari berpikir tentang template dan pengontrol sebagai terpisah entitas ke dalam pemikiran mereka sebagai bagian terpadu dari konstruksi Komponen - ini adalah salah satu aspek utama dari model mental ng2.

Berpikir seperti itu, jelas kita mengharapkan privatevariabel pada kelas komponen agar terlihat dalam templatnya, untuk alasan yang sama kita mengharapkan mereka terlihat dalam privatemetode pada kelas itu.

menggambar moore
sumber
3
Pertama, saya pikir sama seperti Anda drewmoore. Tapi saya memutakhirkan tslint ke 4.02 dan codelyzer ke 2.0.0-beta.1 dan saya memiliki kesalahan mengatakan saya tidak bisa menggunakan pribadi ketika mengakses variabel yang terlihat. Jadi jawaban @ Yaroslav sepertinya lebih tepat.
maxime1992
8
Saya setuju bahwa tidak masuk akal untuk model komponen untuk tidak dapat melihat variabel privatnya, mereka mungkin harus dihaluskan ke dalam kelas yang sama selama kompilasi, maksud saya, Anda harus mengekspos sifat-sifat khusus komponen, objek dan fungsi untuk semua komponen lain sehingga Anda dapat menggunakannya dalam templat Anda, belum lagi tweak eksternal atau panggilan ke mereka dapat menyebabkan perilaku tak terduga potensial pada komponen yang sudah jadi
Felype
1
@Drewmoore, halo Saya telah mengkode sudut hanya selama beberapa bulan. Saya dihadapkan dengan masalah ini. Apakah ada perdebatan lebih lanjut tentang ini? Karena saya tidak menemukan sesuatu yang spesifik pada pola apa yang harus diikuti. imo, karena layak apa adanya, tampaknya melanggar pemisahan kode.
Edgar
2
@rewmoore, saya harus mengatakan saya sepenuhnya setuju dengan logika anser Anda. dan saya khawatir tim Angular telah sedikit kacau. dalam mode AOT, mereka tidak mengizinkan anggota pribadi, sedangkan pada dokumen mereka mengklaim sebaliknya, yang dalam kasus anggota pribadi benar-benar memperkuat poin Anda dan hanya menambah lebih banyak kekacauan pada topik ini. Dari Documents: "Angular memperlakukan templat komponen sebagai bagian dari komponen. Komponen dan templatnya saling mempercayai secara tersirat. Oleh karena itu, templat komponen itu sendiri dapat mengikat properti apa pun dari komponen itu, dengan atau tanpa dekorator Masukan * @ *. "
Orel Eraki
@drewmoore, Tautan untuk dokumen: angular.io/guide/attribute-directives#appendix-why-add-input (saya tahu ini terutama berfokus pada dekorator Input, tetapi banyak hal yang mereka bicarakan tidak hanya terkait dengan it)
Orel Eraki
16

Meskipun contoh kode menunjukkan pertanyaannya adalah tentang TypeScript tetapi tidak memiliki menandai. Angular2 juga tersedia untuk Dart dan ini merupakan perbedaan penting untuk Dart.

Di Dart , templat tidak dapat merujuk variabel privat dari kelas komponen, karena Dart berbeda dengan TypeScript secara efektif mencegah akses anggota pribadi dari luar.

Saya masih mendukung @drewmoores untuk memikirkan komponen dan template sebagai satu unit.

Pembaruan (TS) Tampaknya dengan kompilasi offline, akses ke properti pribadi akan menjadi lebih terbatas di Angular2 TS juga https://github.com/angular/angular/issues/11422

Günter Zöchbauer
sumber
2
Apakah mungkin untuk membuat kompiler typescript untuk membatasi variabel pribadi yang dapat diakses oleh tampilan?
Matthew Harwood
Saya tidak tahu Saya rasa tidak.
Günter Zöchbauer
2
Saya akan berpikir bahwa memiliki mereka pribadi dapat mempengaruhi seberapa dapat diuji komponen itu benar? Misalnya, jika saya membuat komponen dalam konteks tes, saya tidak akan dapat memanggil metode pribadi dari pengujian saya untuk mengkonfirmasi bahwa template / interaksi kelas berfungsi. Saya belum mencoba ini, jadi maafkan saya jika ini jelas :)
Sam Storie
Di Dart Anda tidak dapat mengakses anggota pribadi dalam pengujian. Ada banyak diskusi (terlepas dari bahasa) apakah ini harus didukung dan apakah API pribadi harus diuji sama sekali. Menguji API publik harus dapat mencapai setiap jalur kode. Saya pikir ini masuk akal secara umum. Di Dart pribadi adalah per perpustakaan (yang dapat terdiri dari beberapa file) yang membuat API publik cukup luas - IMHO terlalu luas untuk pengujian unit.
Günter Zöchbauer
3

Variabel pribadi dapat digunakan dalam templat komponen. Lihat lembar contekan angular2 untuk panduan: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-setter

Penjelasan lebih rinci tentang anggota publik / swasta dari kelas dalam naskah dapat ditemukan di sini: https://www.typescriptlang.org/docs/handbook/classes.html .

Semua anggota secara default adalah Publik. Anggota publik dapat diakses dari luar kelas komponen bersama dengan instance-kelas. Tetapi anggota pribadi hanya dapat diakses dalam fungsi anggota kelas.

anusreemn
sumber
Saya melihat tautan pertama ( angular.io/guide/component-interaction#!#parent-to-child-setter ) dan saya tidak melihat di mana pun itu menunjukkan bahwa menggunakan variabel pribadi dalam templat ok. Sebaliknya, mereka menggunakan getter dan setter untuk mengakses variabel pribadi dari template.
Sebastien Chartier
3

Solusi dapat menggunakan variabel pribadi dalam file ts dan menggunakan getter.

private _userName = "Test Name";
get userName() {
  return this._userName;
}

Ini adalah pendekatan yang baik karena file ts dan html tetap independen. Bahkan jika Anda mengubah nama variabel _userName dalam file ts, Anda tidak perlu melakukan perubahan apa pun pada file template.

Franklin Pious
sumber
saya berpikir bahwa jika Anda mengubah _userName menjadi _clientName, misalnya, untuk konsistensi, Anda perlu mengubah pengambil untuk mendapatkan clientName ... jadi tidak ada kemenangan
LeagueOfJava
Ini adalah praktik buruk bagi pengguna garis bawah untuk variabel pribadi.
Florian Leitgeb
1
@FlorianLeitgeb Karena itulah dokumen resmi Angular melakukannya ? private _name = '';
ruffin
Maka potongan kode ini tidak ditinjau dengan benar. Mereka mengikuti konvensi gaya, yang dinyatakan dalam panduan gaya di sini . Dan juga di bagian kelas naskah pada halaman mereka di sini tidak menggunakan garis bawah.
Florian Leitgeb
1
@FlorianLeitgeb Jadi apa yang akan menjadi solusi yang diusulkan untuk intersepsi metode penyetel seperti yang ditunjukkan dalam tautan yang diposting oleh ruffin? yaitu Apa yang Anda sebut bidang dukungan pribadi setter Anda?
El Ronnoco
1

Jawaban singkatnya adalah Anda tidak boleh dapat mengakses anggota pribadi dari templat karena secara teknis dipisahkan dari file TS.

Pelamar Ivens
sumber
0

Di tsconfig.app.json jika Anda memberikan opsi 'fullTemplateTypeCheck' dalam opsi kompiler, Anda dapat melihat semua referensi yang tidak valid dalam file html proyek Anda pada saat membangun proyek.

"angularCompilerOptions": {
"enableIvy": true,
"fullTemplateTypeCheck": true

}

Khushbu Suryavanshi
sumber