Saya ingin membuat templat secara dinamis. Ini harus digunakan untuk membangun ComponentType
saat runtime dan menempatkan (bahkan mengganti) di suatu tempat di dalam Komponen hosting.
Sampai RC4 saya gunakan ComponentResolver
, tetapi dengan RC5 saya mendapatkan pesan berikut:
ComponentResolver is deprecated for dynamic compilation.
Use ComponentFactoryResolver together with @NgModule/@Component.entryComponents or ANALYZE_FOR_ENTRY_COMPONENTS provider instead.
For runtime compile only, you can also use Compiler.compileComponentSync/Async.
Saya menemukan dokumen ini ( Angular 2 Synchronous Dynamic Component Creation )
Dan mengerti bahwa saya dapat menggunakan keduanya
- Agak dinamis
ngIf
denganComponentFactoryResolver
. Jika saya melewati komponen yang dikenal di dalam@Component({entryComponents: [comp1, comp2], ...})
- Saya dapat menggunakan.resolveComponentFactory(componentToRender);
- Kompilasi runtime nyata, dengan
Compiler
...
Tetapi pertanyaannya adalah bagaimana menggunakannya Compiler
? Catatan di atas mengatakan bahwa saya harus menelepon:Compiler.compileComponentSync/Async
- jadi bagaimana caranya?
Sebagai contoh. Saya ingin membuat (berdasarkan beberapa kondisi konfigurasi) jenis template ini untuk satu jenis pengaturan
<form>
<string-editor
[propertyName]="'code'"
[entity]="entity"
></string-editor>
<string-editor
[propertyName]="'description'"
[entity]="entity"
></string-editor>
...
dan dalam kasus lain yang ini ( string-editor
diganti dengan text-editor
)
<form>
<text-editor
[propertyName]="'code'"
[entity]="entity"
></text-editor>
...
Demikian seterusnya (nomor / tanggal / referensi berbedaeditors
berdasarkan tipe properti, melewatkan beberapa properti untuk beberapa pengguna ...) . yaitu ini adalah contoh, konfigurasi sebenarnya dapat menghasilkan templat yang jauh lebih berbeda dan kompleks.
Template berubah, jadi saya tidak bisa menggunakan ComponentFactoryResolver
dan meneruskan yang sudah ada ... Saya butuh solusi dengan Compiler
.
sumber
$compile
sebenarnya bisa dilakukan metode ini tidak bisa - Saya membuat aplikasi di mana saya hanya ingin mengkompilasi HTML ketika masuk melalui halaman pihak ke-3 dan panggilan ajax. Saya tidak dapat menghapus HTML dari halaman dan menempatkannya di templat saya sendiri. SighJawaban:
EDIT - terkait dengan 2.3.0 (2016-12-07)
Topik serupa didiskusikan di sini Setara dengan $ compile di Angular 2 . Kita perlu menggunakan
JitCompiler
danNgModule
. Baca lebih lanjut tentangNgModule
di Angular2 di sini:Pendeknya
Ada plunker / contoh yang berfungsi (template dinamis, tipe komponen dinamis, modul dinamis,
JitCompiler
,, ... beraksi)Prinsipnya adalah:
1) buat Template
2) temukan
ComponentFactory
di cache - pergi ke 7)3) - buat
Component
4) - buat
Module
5) - kompilasi
Module
6) - kembali (dan cache untuk digunakan nanti)
ComponentFactory
7) gunakan Target dan
ComponentFactory
untuk membuat Instance dinamisComponent
Berikut ini cuplikan kode (selengkapnya di sini ) - Pembuat kustom kami kembali hanya dibangun / di-cache
ComponentFactory
dan tampilan yang dikonsumsi placeholder target untuk membuat turunan dariDynamicComponent
Ini dia - singkatnya. Untuk mendapatkan detail lebih lanjut .. baca di bawah ini
.
TL&DR
Amati plunker dan kembali untuk membaca detail seandainya beberapa cuplikan membutuhkan lebih banyak penjelasan
.
Penjelasan terperinci - Angular2 RC6 ++ & komponen runtime
Di bawah ini deskripsi skenario ini , kami akan
PartsModule:NgModule
(tempat potongan kecil)DynamicModule:NgModule
, yang akan berisi komponen dinamis kami (dan referensiPartsModule
secara dinamis)Component
tipe baru (hanya jika templat telah berubah)RuntimeModule:NgModule
. Modul ini akan berisiComponent
jenis yang dibuat sebelumnyaJitCompiler.compileModuleAndAllComponentsAsync(runtimeModule)
untuk mendapatkanComponentFactory
DynamicComponent
- pekerjaan placeholder View Target danComponentFactory
@Inputs
ke contoh baru (beralih dariINPUT
keTEXTAREA
editing) , mengkonsumsi@Outputs
NgModule
Kami membutuhkan sebuah
NgModule
.Akan ada satu modul untuk semua komponen kecil, misalnya
string-editor
,text-editor
(date-editor
,number-editor
...)Yang kedua akan menjadi modul untuk penanganan barang Dinamis kami. Ini akan berisi komponen hosting dan beberapa penyedia .. yang akan menjadi lajang. Untuk itu kami akan mempublikasikannya dengan cara standar - dengan
forRoot()
Akhirnya, kita membutuhkan modul adhoc, runtime .. tetapi itu akan dibuat nanti, sebagai bagian dari
DynamicTypeBuilder
pekerjaan.Modul keempat, modul aplikasi, adalah orang yang terus menyatakan penyedia kompiler:
Baca (baca) lebih banyak tentang NgModule di sana:
Sebuah Template builder
Dalam contoh kita, kita akan memproses detail entitas semacam ini
Untuk membuat
template
, di plunker ini kami menggunakan pembangun sederhana / naif ini.Trik di sini adalah - itu membangun template yang menggunakan beberapa set properti yang diketahui, misalnya
entity
. Properti seperti itu (-ies) harus menjadi bagian dari komponen dinamis, yang akan kita buat selanjutnya.Untuk membuatnya lebih mudah, kita bisa menggunakan antarmuka untuk mendefinisikan properti, yang bisa digunakan oleh pembuat Template. Ini akan diterapkan oleh tipe Komponen dinamis kami.
Seorang
ComponentFactory
pembangunHal yang sangat penting di sini adalah untuk diingat:
Jadi, kami menyentuh inti dari solusi kami. Builder, akan 1) membuat
ComponentType
2) membuatNgModule
3) kompilasiComponentFactory
4) cache itu untuk digunakan kembali nanti.Ketergantungan yang perlu kami terima:
Dan di sini adalah cuplikan cara mendapatkan
ComponentFactory
:Dan berikut adalah dua metode, yang mewakili cara yang sangat keren cara membuat kelas / tipe yang didekorasi dalam runtime. Tidak hanya
@Component
tetapi juga@NgModule
Penting:
ComponentFactory
digunakan oleh komponen hostingBagian terakhir adalah komponen, yang menampung target untuk komponen dinamis kami, mis
<div #dynamicContentPlaceHolder></div>
. Kami mendapatkan referensi untuk itu dan digunakanComponentFactory
untuk membuat komponen. Singkatnya, dan ini semua bagian dari komponen itu (jika perlu, buka plunker di sini )Mari pertama-tama meringkas pernyataan impor:
Kami baru saja menerima, pembuat template dan komponen. Berikutnya adalah properti yang diperlukan untuk contoh kita (lebih banyak di komentar)
Dalam skenario sederhana ini, komponen hosting kami tidak memilikinya
@Input
. Jadi itu tidak harus bereaksi terhadap perubahan. Namun terlepas dari kenyataan itu (dan harus siap untuk perubahan yang akan datang) - kita perlu memperkenalkan beberapa flag jika komponen sudah (pertama) diinisiasi. Dan hanya dengan begitu kita bisa memulai keajaiban.Akhirnya kita akan menggunakan pembangun komponen kita, dan itu baru dikompilasi / di-cache
ComponentFacotry
. Kami placeholder Sasaran akan diminta untuk instantiate yangComponent
dengan pabrik itu.ekstensi kecil
Juga, kita perlu menyimpan referensi untuk template yang dikompilasi .. untuk dapat melakukannya dengan benar
destroy()
, setiap kali kita akan mengubahnya.selesai
Cukup banyak. Jangan lupa Hancurkan apa pun yang dibangun secara dinamis (ngOnDestroy) . Juga, pastikan untuk melakukan cache dinamis
types
danmodules
jika satu-satunya perbedaan adalah template mereka.Periksa semuanya dalam aksi di sini
sumber
type.builder.ts
seperti yang Anda tunjukkan, saya berharap, bahwa setiap pengguna akan mengerti bagaimana menempatkan semua itu ke dalam konteks ... Semoga ini bisa bermanfaat;)EDIT (26/08/2017) : Solusi di bawah ini berfungsi baik dengan Angular2 dan 4. Saya telah memperbaruinya untuk berisi variabel templat dan klik penangan dan mengujinya dengan Angular 4.3.
Untuk Angular4, ngComponentOutlet seperti yang dijelaskan dalam jawaban Ophir adalah solusi yang jauh lebih baik. Tetapi sekarang ini belum mendukung input & output . Jika [PR ini] ( https://github.com/angular/angular/pull/15362] diterima, akan dimungkinkan melalui instance komponen yang dikembalikan oleh event create.
Ng-dynamic-component mungkin yang terbaik dan paling sederhana solusi sama sekali, tapi saya belum mengujinya.
@Long Field's jawaban tepat! Berikut contoh (sinkron) lain:
Langsung di http://plnkr.co/edit/fdP9Oc .
sumber
ngAfterViewInit
panggilan sederhana denganconst template
tidak akan berfungsi. Tetapi jika tugas Anda adalah mengurangi pendekatan yang dijelaskan di atas (buat template, buat komponen, buat modul, kompilasi, buat pabrik .. buat contoh) ... Anda mungkin melakukannyaSaya pasti tiba di pesta terlambat, tidak ada solusi di sini yang tampaknya membantu saya - terlalu berantakan dan merasa seperti terlalu banyak solusi.
Apa yang saya akhirnya lakukan adalah menggunakan
Angular 4.0.0-beta.6
's ngComponentOutlet .Ini memberi saya solusi terpendek, paling sederhana semua ditulis dalam file komponen dinamis.
my-component
- komponen tempat komponen dinamis di-renderDynamicComponent
- komponen yang akan dibangun secara dinamis dan dirender di dalam komponen-sayaJangan lupa untuk memutakhirkan semua perpustakaan sudut ke ^ Angular 4.0.0
Semoga ini bisa membantu, semoga berhasil!
MEMPERBARUI
Juga berfungsi untuk sudut 5.
sumber
2019 jawaban Juni
Kabar baik! Tampaknya paket @ angular / cdk sekarang memiliki dukungan kelas satu untuk portal !
Pada saat penulisan, saya tidak menemukan dokumen resmi di atas sangat membantu (terutama berkenaan dengan mengirim data ke dan menerima peristiwa dari komponen dinamis). Singkatnya, Anda harus:
Langkah 1) Perbarui
AppModule
Impor
PortalModule
dari@angular/cdk/portal
paket dan daftarkan komponen dinamis Anda di dalamnyaentryComponents
Langkah 2. Opsi A: Jika Anda TIDAK perlu memasukkan data ke dalam dan menerima acara dari komponen dinamis Anda :
Lihat itu dalam aksi
Langkah 2. Opsi B: Jika Anda perlu memasukkan data ke dalam dan menerima acara dari komponen dinamis Anda :
Lihat itu dalam aksi
sumber
Portal
perbedaan pendekatan iningTemplateOutlet
danngComponentOutlet
? 🤔Saya memutuskan untuk memadatkan semua yang saya pelajari menjadi satu file . Ada banyak hal yang perlu diperhatikan di sini terutama dibandingkan sebelum RC5. Perhatikan bahwa file sumber ini termasuk AppModule dan AppComponent.
sumber
Saya punya contoh sederhana untuk menunjukkan bagaimana melakukan komponen dinamis 2 rc6 sudut.
Katakanlah, Anda memiliki template html dinamis = template1 dan ingin memuat dinamis, pertama-tama bungkus ke dalam komponen
di sini template1 sebagai html, mungkin mengandung komponen ng2
Dari rc6, @NgModule harus membungkus komponen ini. @NgModule, sama seperti module di anglarJS 1, ia memisahkan bagian yang berbeda dari aplikasi ng2, jadi:
(Di sini impor RouterModule seperti dalam contoh saya ada beberapa komponen rute di html saya seperti yang Anda lihat nanti)
Sekarang Anda dapat mengkompilasi DynamicModule sebagai:
this.compiler.compileModuleAndAllComponentsAsync(DynamicModule).then( factory => factory.componentFactories.find(x => x.componentType === DynamicComponent))
Dan kita perlu memasukkan di atas di app.moudule.ts untuk memuatnya, silakan lihat app.moudle.ts saya. Untuk detail lebih lanjut dan lengkap, periksa: https://github.com/Longfld/DynamicalRouter/blob/master/app/MyRouterLink.ts dan app.moudle.ts
dan lihat demo: http://plnkr.co/edit/1fdAYP5PAbiHdJfTKgWo?p=preview
sumber
Dalam sudut 7.x saya menggunakan elemen sudut untuk ini.
Instal @ angular-elements npm i @ angular / elements -s
Buat layanan aksesori.
Perhatikan bahwa tag elemen khusus Anda harus berbeda dengan pemilih komponen sudut. di AppUserIconComponent:
dan dalam hal ini nama tag khusus saya menggunakan "ikon pengguna".
atau seperti ini:
(dalam templat):
Perhatikan bahwa dalam kasus kedua Anda harus meneruskan objek dengan JSON.stringify dan setelah itu parse lagi. Saya tidak dapat menemukan solusi yang lebih baik.
sumber
document.createElement(tagName);
Memecahkan ini dalam versi Angular 2 Final hanya dengan menggunakan direktif dynamicComponent dari ng-dynamic .
Pemakaian:
Di mana templat adalah templat dinamis dan konteks Anda dapat disetel ke model data dinamis apa pun yang Anda inginkan untuk diikat templat.
sumber
Saya ingin menambahkan beberapa detail di atas posting yang sangat bagus ini oleh Radim.
Saya mengambil solusi ini dan mengerjakannya sebentar dan dengan cepat berlari ke beberapa keterbatasan. Saya hanya akan menguraikan itu dan kemudian memberikan solusi untuk itu juga.
Saya membuat pertanyaan lain berdasarkan posting ini, tentang bagaimana mencapai batasan-batasan ini, yang dapat ditemukan di sini:
kompilasi template dinamis rekursif dalam angular2
Saya hanya akan menguraikan jawaban untuk keterbatasan ini, jika Anda mengalami masalah yang sama seperti saya, karena itu membuat solusinya menjadi lebih fleksibel. Akan luar biasa jika plunker awal diperbarui dengan itu juga.
Untuk mengaktifkan detail dinamis bersarang di dalam satu sama lain, Anda harus menambahkan DynamicModule.forRoot () dalam pernyataan impor di type.builder.ts
Selain itu tidak mungkin digunakan
<dynamic-detail>
di dalam salah satu bagian yang menjadi editor string atau editor teks.Untuk mengaktifkannya Anda harus mengubah
parts.module.ts
dandynamic.module.ts
Di dalam
parts.module.ts
Anda harus menambahkanDynamicDetail
diDYNAMIC_DIRECTIVES
Juga di
dynamic.module.ts
Anda harus menghapus dynamicDetail karena sekarang menjadi bagian dari bagianPlunker yang dimodifikasi dapat ditemukan di sini: http://plnkr.co/edit/UYnQHF?p=preview (Saya tidak menyelesaikan masalah ini, saya hanya pembawa pesan :-D)
Akhirnya tidak mungkin untuk menggunakan templateurl di bagian yang dibuat pada komponen dinamis. Solusi (atau solusi. Saya tidak yakin apakah itu bug sudut atau penggunaan kerangka kerja yang salah) adalah membuat kompiler di konstruktor alih-alih menyuntikkannya.
Kemudian gunakan
_compiler
untuk mengkompilasi, lalu templateUrls juga diaktifkan.Semoga ini bisa membantu orang lain!
Salam, Morten
sumber
Menindaklanjuti jawaban Radmin yang luar biasa, ada sedikit penyesuaian yang diperlukan untuk semua orang yang menggunakan angular-cli versi 1.0.0-beta.22 dan yang lebih tinggi.
COMPILER_PROVIDERS
tidak dapat lagi diimpor (untuk detail lihat angular-cli GitHub ).Jadi solusinya ada untuk tidak menggunakan
COMPILER_PROVIDERS
danJitCompiler
diproviders
bagian sama sekali, tetapi gunakanJitCompilerFactory
dari '@ angular / compiler' sebagai gantinya seperti ini di dalam kelas tipe builder:Seperti yang Anda lihat, itu tidak dapat disuntikkan dan dengan demikian tidak memiliki ketergantungan dengan DI. Solusi ini juga dapat digunakan untuk proyek yang tidak menggunakan angular-cli.
sumber
Saya sendiri mencoba melihat bagaimana cara memperbarui RC4 ke RC5 dan karenanya saya menemukan entri ini dan pendekatan baru untuk pembuatan komponen dinamis masih menyimpan sedikit misteri bagi saya, jadi saya tidak akan menyarankan apa pun pada penyelesai pabrik komponen.
Tapi, yang bisa saya sarankan adalah pendekatan yang lebih jelas untuk pembuatan komponen pada skenario ini - cukup gunakan sakelar di templat yang akan membuat penyunting string atau penyunting teks sesuai dengan beberapa kondisi, seperti ini:
Dan omong-omong, "[" dalam ekspresi [prop] memiliki makna, ini menunjukkan data mengikat satu arah, maka Anda dapat dan bahkan harus menghilangkannya jika Anda tahu bahwa Anda tidak perlu mengikat properti ke variabel.
sumber
switch
/case
berisi beberapa keputusan. Tetapi bayangkan bahwa templat yang dihasilkan bisa sangat besar ... dan berbeda untuk setiap entitas, berbeda oleh keamanan, berbeda dengan status entitas, menurut setiap jenis properti (nomor, tanggal, referensi ... editor) ... Dalam kasus seperti itu, Memecahkan ini dengan templat htmlngSwitch
akan membuat file besar, sangat sangat besarhtml
.Ini adalah contoh kontrol Formulir dinamis yang dihasilkan dari server.
https://stackblitz.com/edit/angular-t3mmg6
Contoh ini adalah kontrol Form dinamis dalam komponen add (Di sinilah Anda bisa mendapatkan Formcontrols dari server). Jika Anda melihat metode addcomponent Anda dapat melihat Kontrol Formulir. Dalam contoh ini saya tidak menggunakan bahan bersudut, tetapi berfungsi (saya menggunakan @ kerja). Ini target ke angular 6, tetapi berfungsi di semua versi sebelumnya.
Perlu menambahkan JITComplierFactory untuk AngularVersion 5 ke atas.
Terima kasih
Vijay
sumber
Untuk kasus khusus ini sepertinya menggunakan arahan untuk secara dinamis membuat komponen akan menjadi pilihan yang lebih baik. Contoh:
Di HTML tempat Anda ingin membuat komponen
Saya akan mendekati dan merancang arahan dengan cara berikut.
Jadi dalam teks komponen Anda, string, tanggal, apa pun - apa pun konfigurasi yang Anda berikan dalam HTML pada
ng-container
elemen akan tersedia.Konfigurasi,,
yourConfig
bisa sama dan mendefinisikan metadata Anda.Bergantung pada konfigurasi atau tipe input Anda, arahan harus bertindak sesuai dan dari jenis yang didukung, itu akan membuat komponen yang sesuai. Jika tidak, ini akan mencatat kesalahan.
sumber
Membangun di atas jawaban oleh Ophir Stern, di sini adalah varian yang bekerja dengan AoT di Angular 4. Satu-satunya masalah yang saya miliki adalah saya tidak bisa menyuntikkan layanan apa pun ke dalam DynamicComponent, tetapi saya bisa hidup dengan itu.
Catatan: Saya belum diuji dengan Angular 5.
Semoga ini membantu.
Bersulang!
sumber