angular - trailer - এন্থিরান




আমি কৌনিক 2.0 এর সাথে ডায়নামিক কম্পোনেন্ট সংকলন করতে কীভাবে গতিশীল টেম্পলেট ব্যবহার/তৈরি করতে পারি? (10)

আমি গতিশীলভাবে টেম্পলেট তৈরি করতে চাই। এটি রানটাইম এবং কম্পোজেন্ট টাইপটি হোস্টিং উপাদানগুলির ভিতরে কোথাও স্থাপন করতে (এমনকি প্রতিস্থাপন) করতে ব্যবহার করা উচিত।

আরসি 4 অবধি আমি ComponentResolver রিসলভার ব্যবহার করছিলাম তবে আরসি 5 এর সাথে আমি বার্তাটি পেয়েছি:

গতিশীল সংকলনের জন্য ComponentResolver রিসলভার অবচিত করা হয়েছে। পরিবর্তে @NgModule/@Component.entryComponents বা ANALYZE_FOR_ENTRY_COMPONENTS সরবরাহকারীর সাথে একত্রে @NgModule/@Component.entryComponents রিসলবারটি ব্যবহার করুন। কেবল রানটাইম সংকলনের জন্য , আপনি Compiler.compileComponentSync/Async ব্যবহার করতে পারেন Compiler.compileComponentSync/Async

আমি এটি (অফিকাল কৌণিক 2) নথিটি পেয়েছি

কৌণিক 2 সিঙ্ক্রোনাস ডায়নামিক উপাদান তৈরি

এবং বুঝতে পারি যে আমি যে কোনওটি ব্যবহার করতে পারি

  • ComponentFactoryResolver ngIf সহ গতিময় ngIf । যদি আমি @Component({entryComponents: [comp1, comp2], ...}) উপাদানগুলির একটি অভ্যন্তরের হোস্টিংয়ের জন্য পরিচিত উপাদানগুলি পাস @Component({entryComponents: [comp1, comp2], ...}) - আমি .resolveComponentFactory(componentToRender); ব্যবহার করতে পারি .resolveComponentFactory(componentToRender);
  • সংকলক সহ বাস্তব রানটাইম সংকলন ...

তবে প্রশ্নটি কীভাবে সেই Compiler ব্যবহার করবেন? উপরের নোটটি বলেছে যে আমার কল করা উচিত: Compiler.compileComponentSync/Async - তবে কীভাবে?

উদাহরণ স্বরূপ. আমি এক ধরণের সেটিংসের জন্য এই ধরণের টেম্পলেট তৈরি করতে (কিছু কনফিগারেশনের শর্তগুলির ভিত্তিতে) তৈরি করতে চাই

<form>
   <string-editor
     [propertyName]="'code'"
     [entity]="entity"
   ></string-editor>
   <string-editor
     [propertyName]="'description'"
     [entity]="entity"
   ></string-editor>
   ...

এবং অন্য এক ক্ষেত্রে এই ( string-editor text-editor দিয়ে প্রতিস্থাপন করা হয়েছে)

<form>
   <text-editor
     [propertyName]="'code'"
     [entity]="entity"
   ></text-editor>
   ...

এবং এইভাবে (সম্পত্তি নম্বর অনুসারে বিভিন্ন নম্বর / তারিখ / রেফারেন্স editors , কিছু ব্যবহারকারীর জন্য কিছু সম্পত্তি এড়িয়ে গেছেন ...) । যেমন এটি একটি উদাহরণ, বাস্তব কনফিগারেশন অনেক বেশি আলাদা এবং জটিল টেম্পলেট তৈরি করতে পারে।

টেমপ্লেটটি পরিবর্তন হচ্ছে , সুতরাং আমি ComponentFactoryResolver ব্যবহার করতে পারি না এবং বিদ্যমানগুলি পাস করতে পারি না ... Compiler সাথে আমার সমাধানের প্রয়োজন

এওটি এবং জিটকম্পিলার (প্রাক্তন রানটাইমকম্পাইলার)

আপনি কি এওটি (সময় সংকলনের আগে) এর সাথে এই বৈশিষ্ট্যগুলি ব্যবহার করতে চান? তুমি কি পাচ্ছ:

ত্রুটি: স্ট্যাটিকভাবে প্রতীক মানগুলি সমাধান করার সময় ত্রুটি হয়েছে। ফাংশন কলগুলি সমর্থিত নয়। রফতানি ফাংশন (মূল .ts ফাইলের মধ্যে 65:17 অবস্থান) এর সাথে একটি ফাংশন বা ল্যাম্বডা প্রতিস্থাপনের কথা বিবেচনা করুন ... / নোড_মডিউলগুলি / @angular/compiler/src/compiler.d.ts এ COMPILER_PROVIDERS চিহ্নটি সমাধান করে,

দয়া করে, আপনার মন্তব্য এখানে রাখুন, এখানে ভোট দিন:

COMPILER_PROVIDERS ব্যবহার করে কোড কি AOT দ্বারা সমর্থিত হবে?


সম্পাদনা - 2.3.0 সম্পর্কিত (২০১-12-১২-০7)

দ্রষ্টব্য: পূর্ববর্তী সংস্করণে সমাধান পেতে, এই পোস্টের ইতিহাসটি পরীক্ষা করুন

অনুরূপ বিষয়টি এখানে কৌণিক 2 এ ile সংকলনের সমতুল্য আলোচনা করা হয়। আমাদের JitCompiler এবং NgModule ব্যবহার করা দরকার। NgModule এ এনজিএমডুল সম্পর্কে আরও পড়ুন:

সংক্ষেপে

এখানে একটি কার্যকারী প্লঙ্কার / উদাহরণ রয়েছে (ডায়নামিক টেম্পলেট, ডায়নামিক উপাদান প্রকার, গতিশীল মডিউল, JitCompiler , ... ক্রিয়ায়)

অধ্যক্ষ হলেন:
1) টেমপ্লেট তৈরি করুন
2) ক্যাশে ComponentFactory সন্ধান করুন - 7 এ যান )
3) - Component তৈরি করুন
4) - Module তৈরি করুন
5) - Module সংকলন
6) - রিটার্ন (এবং পরে ব্যবহারের জন্য ক্যাশে) ComponentFactory
)) গতিশীল Component একটি ইনস্ট্যান্স তৈরি করতে লক্ষ্য এবং ComponentFactory ব্যবহার করুন

এখানে একটি কোড স্নিপেট রয়েছে (এর আরও এখানে ) - আমাদের কাস্টম DynamicComponent কেবল বিল্ট / ক্যাশেড ComponentFactory DynamicComponent এবং DynamicComponent ComponentFactory একটি উদাহরণ তৈরি করতে লক্ষ্য স্থানধারকটি উপভোগ DynamicComponent

  // here we get a TEMPLATE with dynamic content === TODO
  var template = this.templateBuilder.prepareTemplate(this.entity, useTextarea);

  // here we get Factory (just compiled or from cache)
  this.typeBuilder
      .createComponentFactory(template)
      .then((factory: ComponentFactory<IHaveDynamicData>) =>
    {
        // Target will instantiate and inject component (we'll keep reference to it)
        this.componentRef = this
            .dynamicComponentTarget
            .createComponent(factory);

        // let's inject @Inputs to component instance
        let component = this.componentRef.instance;

        component.entity = this.entity;
        //...
    });

সংক্ষেপে এটি - এটি। আরও বিশদ পেতে .. নীচে পড়ুন

টি এল & ডিআর

কোনও প্লাঙ্কার পর্যবেক্ষণ করুন এবং কিছু স্নিপেটের আরও ব্যাখ্যা প্রয়োজন হলে বিশদটি পড়তে ফিরে আসুন

বিশদ ব্যাখ্যা - Angular2 RC6 ++ & রানটাইম উপাদানগুলি

এই দৃশ্যের বর্ণনার নীচে, আমরা করব

  1. একটি মডিউল PartsModule:NgModule তৈরি করুন PartsModule:NgModule (ছোট ছোট PartsModule:NgModule )
  2. আর একটি মডিউল ডায়নামিকমডিউল তৈরি করুন DynamicModule:NgModule , এতে আমাদের গতিশীল উপাদান থাকবে (এবং PartsModule উল্লেখ করা হবে)
  3. গতিশীল টেম্পলেট তৈরি করুন (সহজ পদ্ধতির)
  4. নতুন Component প্রকার তৈরি করুন (কেবলমাত্র টেমপ্লেট পরিবর্তিত হলে)
  5. নতুন RuntimeModule:NgModule তৈরি করুন RuntimeModule:NgModule । এই মডিউলটিতে পূর্বে নির্মিত Component ধরণ থাকবে
  6. ComponentFactory পেতে JitCompiler.compileModuleAndAllComponentsAsync(runtimeModule) কল করুন
  7. DynamicComponent ComponentFactory একটি ইনস্ট্যান্স তৈরি করুন - ভিউ টার্গেটের স্থানধারক এবং ComponentFactory DynamicComponent কাজ
  8. নতুন @Inputs বরাদ্দ করুন ( INPUT থেকে TEXTAREA সম্পাদনায় স্যুইচ করুন) , @Outputs গ্রাস @Outputs

NgModule

আমাদের একটি NgModule এস দরকার।

যদিও আমি খুব সাধারণ উদাহরণটি দেখাতে চাই, এই ক্ষেত্রে আমার তিনটি মডিউল লাগবে (আসলে 4 - তবে আমি অ্যাপমোডুল গণনা করি না) । দয়া করে সত্যিকারের শক্ত গতিশীল উপাদান জেনারেটরের ভিত্তি হিসাবে সাধারণ স্নিপেটের চেয়ে এটি নিন

সমস্ত ছোট ছোট উপাদানের জন্য একটি মডিউল থাকবে, যেমন string-editor , text-editor ( date-editor , number-editor ...)

@NgModule({
  imports:      [ 
      CommonModule,
      FormsModule
  ],
  declarations: [
      DYNAMIC_DIRECTIVES
  ],
  exports: [
      DYNAMIC_DIRECTIVES,
      CommonModule,
      FormsModule
  ]
})
export class PartsModule { }

যেখানে DYNAMIC_DIRECTIVES এক্সটেনসিবল এবং আমাদের গতিশীল উপাদান টেম্পলেট / প্রকারের জন্য ব্যবহৃত সমস্ত ছোট ছোট অংশগুলি ধারণ করার উদ্দেশ্যে রয়েছে। অ্যাপ / পার্টস / পার্টস.মডিউল.টগুলি পরীক্ষা করুন

দ্বিতীয়টি আমাদের গতিশীল স্টাফ হ্যান্ডলিংয়ের জন্য মডিউল হবে। এটিতে হোস্টিং উপাদান এবং কিছু সরবরাহকারী থাকবে .. যা একক হবে। এর জন্য আমরা তাদের স্ট্যান্ডার্ড উপায়ে প্রকাশ করব - forRoot()

import { DynamicDetail }          from './detail.view';
import { DynamicTypeBuilder }     from './type.builder';
import { DynamicTemplateBuilder } from './template.builder';

@NgModule({
  imports:      [ PartsModule ],
  declarations: [ DynamicDetail ],
  exports:      [ DynamicDetail],
})

export class DynamicModule {

    static forRoot()
    {
        return {
            ngModule: DynamicModule,
            providers: [ // singletons accross the whole app
              DynamicTemplateBuilder,
              DynamicTypeBuilder
            ], 
        };
    }
}

forRoot()forRoot() এর ব্যবহার পরীক্ষা করুন

শেষ অবধি, আমাদের একটি অ্যাডহক, রানটাইম মডিউল প্রয়োজন হবে .. তবে এটি পরে তৈরি করা হবে, DynamicTypeBuilder কাজের অংশ হিসাবে।

সামনে মডিউল, অ্যাপ্লিকেশন মডিউল, হ'ল সংকলক সরবরাহকারী ঘোষণা করে:

...
import { COMPILER_PROVIDERS } from '@angular/compiler';    
import { AppComponent }   from './app.component';
import { DynamicModule }    from './dynamic/dynamic.module';

@NgModule({
  imports:      [ 
    BrowserModule,
    DynamicModule.forRoot() // singletons
  ],
  declarations: [ AppComponent],
  providers: [
    COMPILER_PROVIDERS // this is an app singleton declaration
  ],

এনজিডমডুল সম্পর্কে আরও পড়ুন (পড়ুন) সেখানে:

একটি টেম্পলেট নির্মাতা

আমাদের উদাহরণে আমরা এই ধরণের সত্তাটির বিশদ প্রক্রিয়া করব

entity = { 
    code: "ABC123",
    description: "A description of this Entity" 
};

একটি template তৈরি করতে, এই প্লামকারে আমরা এই সাধারণ / নিষ্পাপ নির্মাতা ব্যবহার করি।

আসল সমাধান, একটি প্রকৃত টেম্পলেট নির্মাতা, সেই জায়গা যেখানে আপনার অ্যাপ্লিকেশন অনেক কিছু করতে পারে

// plunker - app/dynamic/template.builder.ts
import {Injectable} from "@angular/core";

@Injectable()
export class DynamicTemplateBuilder {

    public prepareTemplate(entity: any, useTextarea: boolean){

      let properties = Object.keys(entity);
      let template = "<form >";
      let editorName = useTextarea 
        ? "text-editor"
        : "string-editor";

      properties.forEach((propertyName) =>{
        template += `
          <${editorName}
              [propertyName]="'${propertyName}'"
              [entity]="entity"
          ></${editorName}>`;
      });

      return template + "</form>";
    }
}

এখানে একটি কৌশলটি - এটি একটি টেম্পলেট তৈরি করে যা পরিচিত বৈশিষ্ট্যের কিছু সেট, যেমন entity । এই জাতীয় সম্পত্তি (-ies) অবশ্যই গতিশীল উপাদানগুলির অংশ হতে হবে, যা আমরা পরবর্তী তৈরি করব।

এটিকে কিছুটা আরও সহজ করার জন্য, আমরা বৈশিষ্ট্যগুলি সংজ্ঞায়িত করতে একটি ইন্টারফেস ব্যবহার করতে পারি, যা আমাদের টেমপ্লেট নির্মাতা ব্যবহার করতে পারেন। এটি আমাদের গতিশীল উপাদান ধরণের দ্বারা প্রয়োগ করা হবে।

export interface IHaveDynamicData { 
    public entity: any;
    ...
}

একটি ComponentFactory নির্মাতা

এখানে খুব গুরুত্বপূর্ণ জিনিসটি মনে রাখা:

আমাদের উপাদান টাইপ, আমাদের DynamicTypeBuilder দিয়ে তৈরি, পৃথক হতে পারে - তবে শুধুমাত্র এটির টেমপ্লেট (উপরে তৈরি) দ্বারা । উপাদানগুলির বৈশিষ্ট্য (ইনপুট, আউটপুট বা কিছু সুরক্ষিত) এখনও একই। আমাদের যদি আলাদা আলাদা বৈশিষ্ট্যের প্রয়োজন হয় তবে আমাদের টেমপ্লেট এবং টাইপ বিল্ডারের বিভিন্ন সংমিশ্রণটি সংজ্ঞায়িত করা উচিত

সুতরাং, আমরা আমাদের সমাধানের মূলটি স্পর্শ করছি। বিল্ডার, 1) ComponentType 2 তৈরি করবে) এটির NgModule 3 তৈরি করবে) NgModule 4 সংকলন করবে) পরে পুনরায় ব্যবহারের জন্য এটি ক্যাশে করবে।

আমাদের যে নির্ভরতা অর্জন করতে হবে:

// plunker - app/dynamic/type.builder.ts
import { JitCompiler } from '@angular/compiler';

@Injectable()
export class DynamicTypeBuilder {

  // wee need Dynamic component builder
  constructor(
    protected compiler: JitCompiler
  ) {}

ComponentFactory কীভাবে পাবেন তা এখানে একটি স্নিপেট রয়েছে:

// plunker - app/dynamic/type.builder.ts
// this object is singleton - so we can use this as a cache
private _cacheOfFactories:
     {[templateKey: string]: ComponentFactory<IHaveDynamicData>} = {};

public createComponentFactory(template: string)
    : Promise<ComponentFactory<IHaveDynamicData>> {    
    let factory = this._cacheOfFactories[template];

    if (factory) {
        console.log("Module and Type are returned from cache")

        return new Promise((resolve) => {
            resolve(factory);
        });
    }

    // unknown template ... let's create a Type for it
    let type   = this.createNewComponent(template);
    let module = this.createComponentModule(type);

    return new Promise((resolve) => {
        this.compiler
            .compileModuleAndAllComponentsAsync(module)
            .then((moduleWithFactories) =>
            {
                factory = _.find(moduleWithFactories.componentFactories
                                , { componentType: type });

                this._cacheOfFactories[template] = factory;

                resolve(factory);
            });
    });
}

উপরে আমরা উভয় Component এবং Module তৈরি এবং ক্যাশে করি। কারণ যদি টেম্পলেটটি (বাস্তবে সেই সমস্তের প্রকৃত গতিশীল অংশ) একই হয় তবে আমরা পুনরায় ব্যবহার করতে পারি

এবং এখানে দুটি পদ্ধতি রয়েছে যা রানটাইমটিতে সজ্জিত শ্রেণি / প্রকারগুলি কীভাবে তৈরি করা যায় তা দুর্দান্ত উপস্থাপন করে। কেবলমাত্র @Component নয় @NgModule

protected createNewComponent (tmpl:string) {
  @Component({
      selector: 'dynamic-component',
      template: tmpl,
  })
  class CustomDynamicComponent  implements IHaveDynamicData {
      @Input()  public entity: any;
  };
  // a component for this particular template
  return CustomDynamicComponent;
}
protected createComponentModule (componentType: any) {
  @NgModule({
    imports: [
      PartsModule, // there are 'text-editor', 'string-editor'...
    ],
    declarations: [
      componentType
    ],
  })
  class RuntimeComponentModule
  {
  }
  // a module for just this Type
  return RuntimeComponentModule;
}

গুরুত্বপূর্ণ:

আমাদের উপাদান গতিশীল প্রকারভেদ পৃথক, কিন্তু কেবল টেমপ্লেট দ্বারা। সুতরাং আমরা সেগুলি তাদের ক্যাশে করতে ব্যবহার করি। এটি সত্যিই খুব গুরুত্বপূর্ণ। Angular2 এগুলিকেও ক্যাশে করবে .. টাইপ করে । এবং যদি আমরা একই ধরণের টেমপ্লেটগুলিকে নতুন ধরণের জন্য পুনরায় তৈরি করি ... আমরা মেমরি ফাঁস উত্পন্ন করা শুরু করব।

ComponentFactory হোস্টিং উপাদান দ্বারা ব্যবহৃত

ফাইনাল <div #dynamicContentPlaceHolder></div> এমন একটি উপাদান যা আমাদের গতিশীল উপাদানগুলির জন্য <div #dynamicContentPlaceHolder></div> হোস্ট করে, যেমন <div #dynamicContentPlaceHolder></div> । আমরা এটির একটি রেফারেন্স পাই এবং একটি উপাদান তৈরি করতে ComponentFactory ব্যবহার করি। এটি সংক্ষেপে, এবং এখানে সেই উপাদানটির সমস্ত টুকরা এখানে রয়েছে (যদি প্রয়োজন হয় তবে এখানে খোলার চূড়ান্ত )

প্রথমে আমদানি বিবৃতিগুলির সংক্ষিপ্তসার করা যাক:

import {Component, ComponentRef,ViewChild,ViewContainerRef}   from '@angular/core';
import {AfterViewInit,OnInit,OnDestroy,OnChanges,SimpleChange} from '@angular/core';

import { IHaveDynamicData, DynamicTypeBuilder } from './type.builder';
import { DynamicTemplateBuilder }               from './template.builder';

@Component({
  selector: 'dynamic-detail',
  template: `
<div>
  check/uncheck to use INPUT vs TEXTAREA:
  <input type="checkbox" #val (click)="refreshContent(val.checked)" /><hr />
  <div #dynamicContentPlaceHolder></div>  <hr />
  entity: <pre>{{entity | json}}</pre>
</div>
`,
})
export class DynamicDetail implements AfterViewInit, OnChanges, OnDestroy, OnInit
{ 
    // wee need Dynamic component builder
    constructor(
        protected typeBuilder: DynamicTypeBuilder,
        protected templateBuilder: DynamicTemplateBuilder
    ) {}
    ...

আমরা কেবলমাত্র টেমপ্লেট এবং উপাদান বিল্ডারগুলি গ্রহণ করি। এরপরে এমন বৈশিষ্ট্য রয়েছে যা আমাদের উদাহরণের জন্য প্রয়োজনীয় (মন্তব্যগুলিতে আরও)

// reference for a <div> with #dynamicContentPlaceHolder
@ViewChild('dynamicContentPlaceHolder', {read: ViewContainerRef}) 
protected dynamicComponentTarget: ViewContainerRef;
// this will be reference to dynamic content - to be able to destroy it
protected componentRef: ComponentRef<IHaveDynamicData>;

// until ngAfterViewInit, we cannot start (firstly) to process dynamic stuff
protected wasViewInitialized = false;

// example entity ... to be recieved from other app parts
// this is kind of candiate for @Input
protected entity = { 
    code: "ABC123",
    description: "A description of this Entity" 
  };

এই সাধারণ @Input , আমাদের হোস্টিং উপাদানটির কোনও @Input । সুতরাং এটি পরিবর্তন সম্পর্কে প্রতিক্রিয়া জানাতে হবে না। তবে সে সত্যটি থাকা সত্ত্বেও (এবং আগত পরিবর্তনগুলির জন্য প্রস্তুত থাকতে হবে) - উপাদানটি ইতিমধ্যে (প্রথম দিকে) শুরু করা থাকলে আমাদের কিছু পতাকা প্রবর্তন করতে হবে। এবং কেবল তখনই আমরা যাদুটি শুরু করতে পারি।

অবশেষে আমরা আমাদের উপাদান প্রস্তুতকারক এবং এটির সংকলিত / ক্যাশেড ComponentFacotry । আমাদের টার্গেট প্লেসোল্ডারকে সেই কারখানাটি দিয়ে উপাদানটি ইনস্ট্যান্ট করতে বলা হবে।

protected refreshContent(useTextarea: boolean = false){

  if (this.componentRef) {
      this.componentRef.destroy();
  }

  // here we get a TEMPLATE with dynamic content === TODO
  var template = this.templateBuilder.prepareTemplate(this.entity, useTextarea);

  // here we get Factory (just compiled or from cache)
  this.typeBuilder
      .createComponentFactory(template)
      .then((factory: ComponentFactory<IHaveDynamicData>) =>
    {
        // Target will instantiate and inject component (we'll keep reference to it)
        this.componentRef = this
            .dynamicComponentTarget
            .createComponent(factory);

        // let's inject @Inputs to component instance
        let component = this.componentRef.instance;

        component.entity = this.entity;
        //...
    });
}

ছোট এক্সটেনশন

এছাড়াও, আমাদের সঙ্কলিত টেমপ্লেটগুলির একটি রেফারেন্স রাখা দরকার .. এটি যথাযথভাবে destroy() করতে সক্ষম হতে destroy() , যখনই আমরা এটি পরিবর্তন করব।

// this is the best moment where to start to process dynamic stuff
public ngAfterViewInit(): void
{
    this.wasViewInitialized = true;
    this.refreshContent();
}
// wasViewInitialized is an IMPORTANT switch 
// when this component would have its own changing @Input()
// - then we have to wait till view is intialized - first OnChange is too soon
public ngOnChanges(changes: {[key: string]: SimpleChange}): void
{
    if (this.wasViewInitialized) {
        return;
    }
    this.refreshContent();
}

public ngOnDestroy(){
  if (this.componentRef) {
      this.componentRef.destroy();
      this.componentRef = null;
  }
}

সম্পন্ন

এটা প্রায় কাছাকাছি। ডায়নামিকভাবে যা কিছু নির্মিত হয়েছিল তা ধ্বংস করতে ভুলবেন না (ngOnDestroy) । এছাড়াও, গতিশীল types এবং modules ক্যাশে করার বিষয়ে নিশ্চিত হন যদি কেবলমাত্র পার্থক্য তাদের টেম্পলেট is

এখানে সমস্ত কর্মে এটি পরীক্ষা করে দেখুন

এই পোস্টটির পূর্ববর্তী সংস্করণগুলি (উদাঃ আরসি 5 সম্পর্কিত) দেখতে history পরীক্ষা করুন


আমি নিজেও দেখার চেষ্টা করছি যে কীভাবে আমি আরসি 4 কে আরসি 5 এ আপডেট করতে পারি এবং এইভাবে আমি এই এন্ট্রিতে হোঁচট খেয়েছি এবং ডায়নামিক উপাদান তৈরির নতুন পদ্ধতির বিষয়টি এখনও আমার কাছে কিছুটা রহস্য ধারণ করে, তাই আমি উপাদান ফ্যাক্টরি রিসলভার সম্পর্কে কোনও পরামর্শ দেব না।

তবে, আমি যা বলতে পারি এটি এই দৃশ্যে উপাদান তৈরির ক্ষেত্রে আরও স্পষ্ট পদ্ধতি - টেমপ্লেটে স্যুইচ ব্যবহার করুন যা কিছু শর্ত অনুসারে স্ট্রিং এডিটর বা পাঠ্য সম্পাদক তৈরি করবে:

<form [ngSwitch]="useTextarea">
    <string-editor *ngSwitchCase="false" propertyName="'code'" 
                 [entity]="entity"></string-editor>
    <text-editor *ngSwitchCase="true" propertyName="'code'" 
                 [entity]="entity"></text-editor>
</form>

এবং যাইহোক, "["] [প্রপ] এক্সপ্রেশনটির একটি অর্থ রয়েছে, এটি এক উপায়ে ডেটা বাঁধাইয়ের ইঙ্গিত দেয়, অতএব আপনি যদি জানেন যে আপনার যদি ভেরিয়েবলের সাথে সম্পত্তি বাঁধার প্রয়োজন না হয় তবে আপনি সেই ক্ষেত্রে বাদ দিতে পারেন।


এটি সার্ভার থেকে উত্পন্ন গতিশীল ফর্ম নিয়ন্ত্রণগুলির উদাহরণ।

https://stackblitz.com/edit/angular-t3mmg6

এই উদাহরণটি হ'ল গতিশীল ফর্ম নিয়ন্ত্রণগুলি সংযোজন উপাদানগুলিতে থাকে (এটি সেখান থেকে আপনি সার্ভার থেকে ফর্মকন্ট্রোলগুলি পেতে পারেন)। আপনি যদি সংযোজন পদ্ধতিটি দেখেন তবে আপনি ফর্ম নিয়ন্ত্রণগুলি দেখতে পারেন। এই উদাহরণে আমি কৌনিক উপাদান ব্যবহার করছি না, তবে এটি কাজ করে (আমি @ ওয়ার্ক ব্যবহার করছি)। এটি কৌণিক 6 এর লক্ষ্যবস্তু, তবে সমস্ত পূর্ববর্তী সংস্করণে কাজ করে।

অ্যাঙ্গুলার ভার্সন 5 এবং তারপরের জন্য জেআইটিকম্প্পিয়ারফ্যাক্টরি যুক্ত করা দরকার।

ধন্যবাদ

বিজয়


ওফির স্টার্নের উত্তরের শীর্ষে বিল্ডিং, এখানে একটি বৈকল্পিক যা কৌণিক 4 এওটি-র সাথে কাজ করে The কেবলমাত্র আমার কাছে সমস্যা হ'ল আমি ডায়নামিক কম্পোনেন্টে কোনও পরিষেবা ইনজেক্ট করতে পারি না, তবে আমি তার সাথে বেঁচে থাকতে পারি।

দ্রষ্টব্য: আমি কৌনিক 5 এর সাথে পরীক্ষা করিনি।

import { Component, OnInit, Input, NgModule, NgModuleFactory, Compiler, EventEmitter, Output } from '@angular/core';
import { JitCompilerFactory } from '@angular/compiler';

export function createJitCompiler() {
  return new JitCompilerFactory([{
    useDebug: false,
    useJit: true
  }]).createCompiler();
}

type Bindings = {
  [key: string]: any;
};

@Component({
  selector: 'app-compile',
  template: `
    <div *ngIf="dynamicComponent && dynamicModule">
      <ng-container *ngComponentOutlet="dynamicComponent; ngModuleFactory: dynamicModule;">
      </ng-container>
    </div>
  `,
  styleUrls: ['./compile.component.scss'],
  providers: [{provide: Compiler, useFactory: createJitCompiler}]
})
export class CompileComponent implements OnInit {

  public dynamicComponent: any;
  public dynamicModule: NgModuleFactory<any>;

  @Input()
  public bindings: Bindings = {};
  @Input()
  public template: string = '';

  constructor(private compiler: Compiler) { }

  public ngOnInit() {

    try {
      this.loadDynamicContent();
    } catch (err) {
      console.log('Error during template parsing: ', err);
    }

  }

  private loadDynamicContent(): void {

    this.dynamicComponent = this.createNewComponent(this.template, this.bindings);
    this.dynamicModule = this.compiler.compileModuleSync(this.createComponentModule(this.dynamicComponent));

  }

  private createComponentModule(componentType: any): any {

    const runtimeComponentModule = NgModule({
      imports: [],
      declarations: [
        componentType
      ],
      entryComponents: [componentType]
    })(class RuntimeComponentModule { });

    return runtimeComponentModule;

  }

  private createNewComponent(template: string, bindings: Bindings): any {

    const dynamicComponent = Component({
      selector: 'app-dynamic-component',
      template: template
    })(class DynamicComponent implements OnInit {

      public bindings: Bindings;

      constructor() { }

      public ngOnInit() {
        this.bindings = bindings;
      }

    });

    return dynamicComponent;

  }

}

আশাকরি এটা সাহায্য করবে.

চিয়ার্স!


কৌণিক 2 আরসি 6 ডায়নামিক উপাদান কীভাবে করবেন তা দেখানোর জন্য আমার একটি সাধারণ উদাহরণ রয়েছে।

বলুন, আপনার একটি ডায়নামিক এইচটিএমএল টেম্পলেট = টেম্পলেট 1 রয়েছে এবং গতিশীল লোড করতে চান, প্রথমে উপাদানটিতে মোড়ানো rap

@Component({template: template1})
class DynamicComponent {}

html হিসাবে টেমপ্লেট 1 এ, এনজি 2 উপাদান থাকতে পারে

আরসি From থেকে, @NgModule এই উপাদানটি মোড়াতে হবে। @ এনজিএমডিউল, ঠিক যেমন অ্যাংলারজেএস 1-এর মডিউল, এটি এনজি 2 অ্যাপ্লিকেশনটির বিভিন্ন অংশকে ডিকুয়াল করে, তাই:

@Component({
  template: template1,

})
class DynamicComponent {

}
@NgModule({
  imports: [BrowserModule,RouterModule],
  declarations: [DynamicComponent]
})
class DynamicModule { }

(এখানে আমার উদাহরণ হিসাবে রাউটারমডুল আমদানি করুন আমার এইচটিএমএলে কিছু রুটের উপাদান রয়েছে যা আপনি পরে দেখতে পাচ্ছেন)

এখন আপনি ডায়নামিকমডুল কে এইভাবে সংকলন করতে পারেন: this.compiler.compileModuleAndAllComponentsAsync(DynamicModule).then( factory => factory.componentFactories.find(x => x.componentType === DynamicComponent))

এটি লোড করার জন্য আমাদের উপরে app.moudule.ts স্থাপন করা দরকার, দয়া করে আমার app.moudle.ts দেখুন। আরও এবং বিশদ বিবরণের জন্য চেক করুন: https://github.com/Longfld/DynamicalRouter/blob/master/app/MyRouterLink.ts এবং app.moudle.ts

এবং ডেমো দেখুন: http://plnkr.co/edit/1fdAYP5PAbiHdJfTKgWo?p=preview


কৌণিক 7.x এ আমি এর জন্য কৌণিক-উপাদান ব্যবহার করেছি।

  1. @ কৌণিক-উপাদান এনপিএম ইনস্টল করুন @ কৌণিক / উপাদানসমূহ- এস

  2. আনুষাঙ্গিক পরিষেবা তৈরি করুন।

import { Injectable, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { IStringAnyMap } from 'src/app/core/models';
import { AppUserIconComponent } from 'src/app/shared';

const COMPONENTS = {
  'user-icon': AppUserIconComponent
};

@Injectable({
  providedIn: 'root'
})
export class DynamicComponentsService {
  constructor(private injector: Injector) {

  }

  public register(): void {
    Object.entries(COMPONENTS).forEach(([key, component]: [string, any]) => {
      const CustomElement = createCustomElement(component, { injector: this.injector });
      customElements.define(key, CustomElement);
    });
  }

  public create(tagName: string, data: IStringAnyMap = {}): HTMLElement {
    const customEl = document.createElement(tagName);

    Object.entries(data).forEach(([key, value]: [string, any]) => {
      customEl[key] = value;
    });

    return customEl;
  }
}

নোট করুন যে আপনার কাস্টম এলিমেন্ট ট্যাগটি অবশ্যই কৌণিক উপাদান নির্বাচকের সাথে পৃথক হতে হবে। অ্যাপ্লিকেশন আইকন কম্পোনেন্টে:

...
selector: app-user-icon
...

এবং এই ক্ষেত্রে কাস্টম ট্যাগ নামটি আমি "ব্যবহারকারী-আইকন" ব্যবহার করেছি।

  1. তারপরে আপনাকে অবশ্যই অ্যাপকোম্পোনটে রেজিস্ট্রার কল করতে হবে:
@Component({
  selector: 'app-root',
  template: '<router-outlet></router-outlet>'
})
export class AppComponent {
  constructor(   
    dynamicComponents: DynamicComponentsService,
  ) {
    dynamicComponents.register();
  }

}
  1. এবং এখন আপনার কোডের যে কোনও জায়গায় আপনি এটি এর মতো ব্যবহার করতে পারেন:
dynamicComponents.create('user-icon', {user:{...}});

বা এই মত:

const html = `<div class="wrapper"><user-icon class="user-icon" user='${JSON.stringify(rec.user)}'></user-icon></div>`;

this.content = this.domSanitizer.bypassSecurityTrustHtml(html);

(টেমপ্লেটে):

<div class="comment-item d-flex" [innerHTML]="content"></div>

নোট করুন যে দ্বিতীয় ক্ষেত্রে আপনাকে অবশ্যই JSON.stringify এর সাথে অবজেক্টগুলি পাস করতে হবে এবং তার পরে এটি আবার বিশ্লেষণ করবে। এর থেকে ভাল সমাধান আমি খুঁজে পাচ্ছি না।


রাদিমের খুব দুর্দান্ত পোস্টটির উপরে আমি কয়েকটি বিবরণ যুক্ত করতে চাই।

আমি এই সমাধানটি নিয়েছি এবং এতে কিছুটা সময় নিয়ে কাজ করেছি এবং দ্রুত কিছুটা সীমাবদ্ধতার মধ্যে চলে এসেছি ran আমি কেবল সেগুলির রূপরেখা করব এবং তারপরে এটির সমাধানও দেব।

  • সবার আগে আমি একটি গতিশীল-বিশদ (মূলত একে অপরের অভ্যন্তরে নীড় গতিশীল UIs) এর ভিতরে গতিশীল-বিশদ রেন্ডার করতে অক্ষম ছিল।
  • পরবর্তী সমস্যাটি হ'ল আমি সমাধানে উপলব্ধ অংশগুলির মধ্যে একটির ভিতরে গতিশীল-বিশদটি সরবরাহ করতে চেয়েছিলাম। প্রাথমিক সমাধান দিয়েও তা সম্ভব হয়নি।
  • শেষ পর্যন্ত স্ট্রিং-এডিটর এর মতো গতিশীল অংশগুলিতে টেম্পলেট URL গুলি ব্যবহার করা সম্ভব ছিল না।

এই সীমাবদ্ধতা কীভাবে অর্জন করা যায়, যা এখানে পাওয়া যাবে তার উপর ভিত্তি করে আমি এই পোস্টের ভিত্তিতে আরেকটি প্রশ্ন করেছি:

কৌণিক 2 তে পুনরাবৃত্ত গতিশীল টেম্পলেট সংকলন

আমি এই সীমাবদ্ধতার উত্তরগুলি কেবল রূপরেখা করব, আপনি কি আমার মতো একই সমস্যাটি চালিত হওয়া উচিত, কারণ এটি সমাধানটিকে আরও নমনীয় করে তোলে। এটির সাথে প্রাথমিক প্লঙ্কার আপডেট করাও দুর্দান্ত লাগবে।

একে অপরের অভ্যন্তরে বাসা বাঁধার গতিশীল-বিশদ সক্ষম করার জন্য, আপনার টাইপ.বিল্ডার.সেটগুলিতে আমদানি বিবৃতিতে ডায়নামিকমডিউল.ফোড় রুট () যুক্ত করতে হবে

protected createComponentModule (componentType: any) {
    @NgModule({
    imports: [
        PartsModule, 
        DynamicModule.forRoot() //this line here
    ],
    declarations: [
        componentType
    ],
    })
    class RuntimeComponentModule
    {
    }
    // a module for just this Type
    return RuntimeComponentModule;
}

এ ছাড়া <dynamic-detail> স্ট্রিং-এডিটর বা টেক্সট-এডিটর হওয়া অংশগুলির একটির অভ্যন্তরে ব্যবহার করা সম্ভব ছিল না ।

এটি সক্ষম করতে আপনাকে পরিবর্তন করতে হবে parts.module.ts এবং dynamic.module.ts

ভিতরে parts.module.ts আপনাকে যুক্ত DynamicDetail করতে হবে DYNAMIC_DIRECTIVES

export const DYNAMIC_DIRECTIVES = [
   forwardRef(() => StringEditor),
   forwardRef(() => TextEditor),
   DynamicDetail
];

এছাড়াও আপনি dynamic.module.ts গতিশীল বিবরণ এখন অংশের অংশ হিসাবে সরানো হবে

@NgModule({
   imports:      [ PartsModule ],
   exports:      [ PartsModule],
})

একটি কাজের পরিবর্তিত প্লাঙ্কার এখানে পাওয়া যাবে: http://plnkr.co/edit/UYnQHF?p=preview (আমি এই সমস্যাটি সমাধান করি নি, আমি কেবল মেসেঞ্জার :- ডি)

শেষ পর্যন্ত গতিশীল উপাদানগুলিতে তৈরি অংশগুলিতে টেমপ্লেটরসগুলি ব্যবহার করা সম্ভব ছিল না। একটি সমাধান (বা কার্যতঃ আমি নিশ্চিত নই যে এটি কৌণিক বাগ বা ফ্রেমওয়ার্কের ভুল ব্যবহার) এটি ইনজেকশনের পরিবর্তে কনস্ট্রাক্টরে একটি সংকলক তৈরি করা হয়েছিল।

    private _compiler;

    constructor(protected compiler: RuntimeCompiler) {
        const compilerFactory : CompilerFactory =
        platformBrowserDynamic().injector.get(CompilerFactory);
        this._compiler = compilerFactory.createCompiler([]);
    }

তারপরে _compiler সংকলনটি ব্যবহার করুন , তারপরে টেমপ্লেটআরলগুলি সক্ষম করা হবে।

return new Promise((resolve) => {
        this._compiler
            .compileModuleAndAllComponentsAsync(module)
            .then((moduleWithFactories) =>
            {
                let _ = window["_"];
                factory = _.find(moduleWithFactories.componentFactories, { componentType: type });

                this._cacheOfFactories[template] = factory;

                resolve(factory);
            });
    });

আশাকরি ইহা অন্য কারো সাহায্য করবে!

শুভেচ্ছা মর্টেন


আমি অবশ্যই পার্টিতে দেরিতে পৌঁছেছি, এগুলির সমাধানগুলির কোনওটিই আমার পক্ষে সহায়ক বলে মনে হয়নি - খুব অগোছালো এবং খুব বেশি কাজের মতো মনে হয়নি felt

আমি যা করতে পেরেছি তা হল Angular 4.0.0-beta.6 এর ngComponentOutlet

এটি আমাকে গতিশীল উপাদানগুলির ফাইলটিতে লিখিততম, সবচেয়ে সহজ সমাধানটি দিয়েছে।

  • এখানে একটি সহজ উদাহরণ যা কেবল পাঠ্য গ্রহণ করে এবং এটি একটি টেম্পলেটে রাখে, তবে স্পষ্টতই আপনি আপনার প্রয়োজন অনুযায়ী পরিবর্তন করতে পারেন:
import {
  Component, OnInit, Input, NgModule, NgModuleFactory, Compiler
} from '@angular/core';

@Component({
  selector: 'my-component',
  template: `<ng-container *ngComponentOutlet="dynamicComponent;
                            ngModuleFactory: dynamicModule;"></ng-container>`,
  styleUrls: ['my.component.css']
})
export class MyComponent implements OnInit {
  dynamicComponent;
  dynamicModule: NgModuleFactory<any>;

  @Input()
  text: string;

  constructor(private compiler: Compiler) {
  }

  ngOnInit() {
    this.dynamicComponent = this.createNewComponent(this.text);
    this.dynamicModule = this.compiler.compileModuleSync(this.createComponentModule(this.dynamicComponent));
  }

  protected createComponentModule (componentType: any) {
    @NgModule({
      imports: [],
      declarations: [
        componentType
      ],
      entryComponents: [componentType]
    })
    class RuntimeComponentModule
    {
    }
    // a module for just this Type
    return RuntimeComponentModule;
  }

  protected createNewComponent (text:string) {
    let template = `dynamically created template with text: ${text}`;

    @Component({
      selector: 'dynamic-component',
      template: template
    })
    class DynamicComponent implements OnInit{
       text: any;

       ngOnInit() {
       this.text = text;
       }
    }
    return DynamicComponent;
  }
}
  • সংক্ষিপ্ত ব্যাখ্যা:
    1. my-component - একটি উপাদান যা একটি গতিশীল উপাদান রেন্ডারিং হয়
    2. ডায়নামিক কম্পোনেন্ট - DynamicComponent তৈরি করা উপাদান এবং এটি আমার-উপাদানটির মধ্যে রেন্ডার হচ্ছে

সমস্ত কৌণিক গ্রন্থাগারকে ular Angular 4.0.0 এ আপগ্রেড করতে ভুলবেন না

ভাগ্য ভালো, এই সাহায্য আশা করি!

হালনাগাদ

কৌনিক 5 এর জন্যও কাজ করে।


আমি শিখেছি সমস্ত কিছুই একটি ফাইলে কম্প্যাক্ট করার সিদ্ধান্ত নিয়েছি । বিশেষত আরসি 5 এর তুলনায় এখানে অনেক কিছু নিতে হবে। নোট করুন যে এই উত্স ফাইলটিতে অ্যাপমোডুল এবং অ্যাপকোম্পোন্ট রয়েছে।

import {
  Component, Input, ReflectiveInjector, ViewContainerRef, Compiler, NgModule, ModuleWithComponentFactories,
  OnInit, ViewChild
} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';

@Component({
  selector: 'app-dynamic',
  template: '<h4>Dynamic Components</h4><br>'
})
export class DynamicComponentRenderer implements OnInit {

  factory: ModuleWithComponentFactories<DynamicModule>;

  constructor(private vcRef: ViewContainerRef, private compiler: Compiler) { }

  ngOnInit() {
    if (!this.factory) {
      const dynamicComponents = {
        sayName1: {comp: SayNameComponent, inputs: {name: 'Andrew Wiles'}},
        sayAge1: {comp: SayAgeComponent, inputs: {age: 30}},
        sayName2: {comp: SayNameComponent, inputs: {name: 'Richard Taylor'}},
        sayAge2: {comp: SayAgeComponent, inputs: {age: 25}}};
      this.compiler.compileModuleAndAllComponentsAsync(DynamicModule)
        .then((moduleWithComponentFactories: ModuleWithComponentFactories<DynamicModule>) => {
          this.factory = moduleWithComponentFactories;
          Object.keys(dynamicComponents).forEach(k => {
            this.add(dynamicComponents[k]);
          })
        });
    }
  }

  addNewName(value: string) {
    this.add({comp: SayNameComponent, inputs: {name: value}})
  }

  addNewAge(value: number) {
    this.add({comp: SayAgeComponent, inputs: {age: value}})
  }

  add(comp: any) {
    const compFactory = this.factory.componentFactories.find(x => x.componentType === comp.comp);
    // If we don't want to hold a reference to the component type, we can also say: const compFactory = this.factory.componentFactories.find(x => x.selector === 'my-component-selector');
    const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
    const cmpRef = this.vcRef.createComponent(compFactory, this.vcRef.length, injector, []);
    Object.keys(comp.inputs).forEach(i => cmpRef.instance[i] = comp.inputs[i]);
  }
}

@Component({
  selector: 'app-age',
  template: '<div>My age is {{age}}!</div>'
})
class SayAgeComponent {
  @Input() public age: number;
};

@Component({
  selector: 'app-name',
  template: '<div>My name is {{name}}!</div>'
})
class SayNameComponent {
  @Input() public name: string;
};

@NgModule({
  imports: [BrowserModule],
  declarations: [SayAgeComponent, SayNameComponent]
})
class DynamicModule {}

@Component({
  selector: 'app-root',
  template: `
        <h3>{{message}}</h3>
        <app-dynamic #ad></app-dynamic>
        <br>
        <input #name type="text" placeholder="name">
        <button (click)="ad.addNewName(name.value)">Add Name</button>
        <br>
        <input #age type="number" placeholder="age">
        <button (click)="ad.addNewAge(age.value)">Add Age</button>
    `,
})
export class AppComponent {
  message = 'this is app component';
  @ViewChild(DynamicComponentRenderer) dcr;

}

@NgModule({
  imports: [BrowserModule],
  declarations: [AppComponent, DynamicComponentRenderer],
  bootstrap: [AppComponent]
})
export class AppModule {}`

সম্পাদনা (26/08/2017) : নীচের সমাধানটি Angular2 এবং 4 এর সাথে ভালভাবে কাজ করে I've আমি এটি টেমপ্লেট ভেরিয়েবল ধারণ করতে আপডেট করেছি এবং হ্যান্ডলারটি ক্লিক করেছি এবং এটি কৌনিক 4.3 দিয়ে পরীক্ষা করেছি।
অ্যাঙ্গুলার 4 এর জন্য, ওপিরের উত্তরে বর্ণিত এনজিপম্পোনটিউটলেট একটি আরও ভাল সমাধান। তবে এখনই এটি ইনপুট এবং আউটপুটগুলিকে সমর্থন করে না । যদি [এই পিআর] ( https://github.com/angular/angular/pull/15362] স্বীকার করা হয়, এটি ইভেন্ট ইভেন্টের মাধ্যমে ফেরত অংশের মাধ্যমে সম্ভব হবে।
ng-dynamic-component সম্পূর্ণরূপে সেরা এবং সহজ সমাধান হতে পারে, তবে আমি এখনও এটি পরীক্ষা করে দেখিনি।

@ লং ফিল্ডের উত্তর স্পট! এখানে আরও একটি (সিঙ্ক্রোনাস) উদাহরণ রয়েছে:

import {Compiler, Component, NgModule, OnInit, ViewChild,
  ViewContainerRef} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'

@Component({
  selector: 'my-app',
  template: `<h1>Dynamic template:</h1>
             <div #container></div>`
})
export class App implements OnInit {
  @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;

  constructor(private compiler: Compiler) {}

  ngOnInit() {
    this.addComponent(
      `<h4 (click)="increaseCounter()">
        Click to increase: {{counter}}
      `enter code here` </h4>`,
      {
        counter: 1,
        increaseCounter: function () {
          this.counter++;
        }
      }
    );
  }

  private addComponent(template: string, properties?: any = {}) {
    @Component({template})
    class TemplateComponent {}

    @NgModule({declarations: [TemplateComponent]})
    class TemplateModule {}

    const mod = this.compiler.compileModuleAndAllComponentsSync(TemplateModule);
    const factory = mod.componentFactories.find((comp) =>
      comp.componentType === TemplateComponent
    );
    const component = this.container.createComponent(factory);
    Object.assign(component.instance, properties);
    // If properties are changed at a later stage, the change detection
    // may need to be triggered manually:
    // component.changeDetectorRef.detectChanges();
  }
}

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App ],
  bootstrap: [ App ]
})
export class AppModule {}

http://plnkr.co/edit/fdP9Oc এ লাইভ।





angular2-compiler