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


196

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

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

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.

আমি এই দস্তাবেজটি পেয়েছি ( কৌণিক 2 সিঙ্ক্রোনাস ডায়নামিক উপাদান তৈরি )

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

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

কিন্তু প্রশ্নটি কীভাবে এটি ব্যবহার করবেন 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


আমি যে সমাধানটি পেয়েছি তা খুব সুন্দর হয়েছিল আমি চাই যে এই প্রশ্নের সন্ধানকারী প্রত্যেকে এই মুহুর্তে একেবারে নীচে খুব নীচে থাকা আমার উত্তরটি দেখুন। :)
রিচার্ড হলটজ


এখানে প্রতিটি একক উত্তর নিয়ে সমস্যা আছে এবং $compileএই পদ্ধতিগুলি আসলে কী করতে পারে তা করতে পারে - আমি একটি অ্যাপ্লিকেশন তৈরি করছি যেখানে আমি কেবল একটি তৃতীয় পক্ষের পৃষ্ঠা এবং এজাক্স কলগুলির মাধ্যমে এইচটিএমএল সংকলন করতে চাই। আমি পৃষ্ঠাটি থেকে এইচটিএমএল সরিয়ে এটি নিজের টেম্পলেটটিতে রাখতে পারি না। দীর্ঘশ্বাস
অগি গার্ডনার

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

উত্তর:


162

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

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

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

সংক্ষেপে

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

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

এখানে একটি কোড স্নিপেট (এটির আরও এখানে ) - আমাদের কাস্টম বিল্ডার কেবল নির্মিত / ক্যাশে ফিরে আসছেন 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 ++ & রানটাইম উপাদান components

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

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

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

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()করুনAppModule

অবশেষে, আমাদের অ্যাডহক, রানটাইম মডিউল প্রয়োজন হবে .. তবে এটি পরে তৈরি করা হবে, 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) তৈরি করবেন ComponentType2) এটি তৈরি করুন NgModule3) সংকলন ComponentFactory4) এটি পুনরায় ব্যবহারের জন্য ক্যাশে করুন

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

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

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

এবং এখানে দুটি পদ্ধতি রয়েছে যা রানটাইমের সময় সজ্জিত শ্রেণি / প্রকারগুলি কীভাবে তৈরি করা যায় তা দুর্দান্ত উপস্থাপন করে । শুধু @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>। আমরা এটিতে একটি রেফারেন্স পাই এবং ComponentFactoryএকটি উপাদান তৈরি করতে ব্যবহার করি । এটি সংক্ষেপে, এবং এখানে component উপাদানগুলির সমস্ত টুকরা এখানে রয়েছে (যদি প্রয়োজন হয় তবে এখানে খোলার চূড়ান্ত )

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

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। সুতরাং এটি পরিবর্তন সম্পর্কে প্রতিক্রিয়া জানাতে হবে না। তবে এই সত্যটি থাকা সত্ত্বেও (এবং আগত পরিবর্তনগুলির জন্য প্রস্তুত থাকতে হবে) - উপাদানটি ইতিমধ্যে (প্রথম দিকে) শুরু করা থাকলে আমাদের কিছু পতাকা প্রবর্তন করতে হবে। এবং কেবল তখনই আমরা যাদুটি শুরু করতে পারি।

শেষ পর্যন্ত আমরা আমাদের উপাদান নির্মাতাকে ব্যবহার করব এবং এটি স্রেফ সংকলিত / ক্যাশেড করব ComponentFacotry । আমাদের লক্ষ্য স্থানধারক instantiate করতে বলা হবে যে কারখানা সঙ্গে।Component

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()এটি যথাযথভাবে সক্ষম হতে , যখনই আমরা এটি পরিবর্তন করব।

// 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কেবলমাত্র পার্থক্য যদি তাদের টেম্পলেট হয়।

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

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


50
এই যেমন জটিল সমাধান মত চেহারা, অবহেলিত এক খুব সহজ এবং পরিষ্কার ছিল, এটি করার অন্য কোন উপায় আছে?
টিবিবাস

3
আমি মনে করি @tibbus এর মতোই: অবহেলিত কোডের সাথে এটি আগের চেয়ে জটিল হয়ে উঠেছে। যদিও আপনার উত্তরের জন্য ধন্যবাদ।
লুসিও মোল্লিনেদো

5
@ রাইবস আপনার নোটের জন্য ধন্যবাদ। আমাকে কিছু স্পষ্ট করা যাক। অন্যান্য অনেক উত্তর এটিকে সহজ করার চেষ্টা করে । তবে আমি এটিকে ব্যাখ্যা করার এবং এটিকে বাস্তব ব্যবহারের জন্য বন্ধ করে একটি দৃশ্যে দেখানোর চেষ্টা করছি । আমাদের স্টাফগুলি ক্যাশে করা দরকার, পুনর্নির্মাণ ইত্যাদিতে আমাদের ডেকে ডেকে আনতে হবে। সুতরাং, গতিশীল বিল্ডিংয়ের যাদুটি যখন type.builder.tsআপনি নির্দেশ করেছেন ঠিক তেমনই আছে, আমি ইচ্ছা করি যে কোনও ব্যবহারকারীর বুঝতে হবে যে কীভাবে এটি সমস্ত স্থাপন করা যায় প্রসঙ্গ ... আশা করি এটি কার্যকর হতে পারে;)
রদিম কাহলর

7
@ রাদিম কাহেলার - আমি এই উদাহরণটি চেষ্টা করেছি। এটি এওটি ছাড়া কাজ করছে। তবে যখন আমি এটিট দিয়ে এটি চালানোর চেষ্টা করেছি তখন এটি ত্রুটিটি দেখায় "রানটাইম কম্পোনেন্টমডুলের জন্য কোনও এনজিএমডুল মেটাডেটা পাওয়া যায় নি"। আপনি এই ত্রুটি সমাধান করতে আমাকে সাহায্য করতে পারেন?
ট্রুশা

4
উত্তর নিজেই নিখুঁত! কিন্তু বাস্তব জীবনের অ্যাপ্লিকেশনগুলি ব্যবহারিক নয়। কৌণিক দলটির কাঠামোর মধ্যে এটির জন্য একটি সমাধান সরবরাহ করা উচিত, কারণ এটি ব্যবসায়ের অ্যাপ্লিকেশনগুলিতে সাধারণ প্রয়োজন। যদি তা না হয় তবে এটি জিজ্ঞাসা করতে হবে যে অ্যাঙ্গুলার 2 ব্যবসায়ের অ্যাপ্লিকেশনগুলির জন্য সঠিক প্ল্যাটফর্ম।
কার্ল

58

সম্পাদনা (২/0/০৮/২০১)) : নীচের সমাধানটি Angular2 এবং 4 এর সাথে ভাল কাজ করে template
অ্যাঙ্গুলার 4-এর জন্য, ওপিরের উত্তরে বর্ণিত এনজিপম্পোনটিউটলেট একটি আরও ভাল সমাধান। তবে এখনই এটি ইনপুট এবং আউটপুটগুলিকে সমর্থন করে না । যদি [এই পিআর] ( https://github.com/angular/angular/pull/15362] স্বীকার করা হয়, এটি ইভেন্ট ইভেন্টের মাধ্যমে ফেরত দেওয়া উপাদানগুলির মাধ্যমে সম্ভব হবে be
এনজি-ডায়নামিক-উপাদানটি সেরা এবং সহজতম হতে পারে পুরোপুরি সমাধান, তবে আমি এখনও এটি পরীক্ষা করে দেখিনি।

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

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 এ লাইভ ।


3
আমি বলতে চাই, এটা দৃষ্টান্তমূলক লিখতে হয় যতটা সম্ভব কম কোড হিসেবে কাজ করতে আমার উত্তর একই stackoverflow.com/a/38888009/1679310 । যদি অবস্থার পরিবর্তন হয় তবে এটি দরকারী-ক্ষেত্রে (বেশিরভাগই পুনরায় উত্পাদনের টেম্পলেট) হওয়া উচিত ... একটি সাধারণ ngAfterViewInitকলটি const templateকাজ করবে না। তবে যদি আপনার কাজটি উপরে বর্ণিত বর্ণিত পদ্ধতির (টেমপ্লেট তৈরি করা, উপাদান তৈরি করা, মডিউল তৈরি করা, সংকলন, কারখানা তৈরি .. উদাহরণ তৈরি করা) হ্রাস করা হয় ... আপনি সম্ভবত এটি করেছেন
Radim Köhler

সমাধানের জন্য ধন্যবাদ: যদিও আমি টেমপ্লেট ইউআরএল এবং শৈলীগুলি লোড করতে সমস্যা করছি তবে আমি নীচের ত্রুটি পেয়েছি: কোনও রিসোর্সলোডার বাস্তবায়ন সরবরাহ করা হয়নি। ইউআরএল লোকালহোস্টটি পড়তে পারবেন না : 3000 / অ্যাপ / পৃষ্ঠাগুলি / পৃষ্ঠাগুলি_কমোন.এসএস , আমি কী অনুপস্থিত তার কোনও ধারণা?
জেরার্ডলামো

গ্রিডে নিয়ন্ত্রণের মতো নির্দিষ্ট ডেটা সহ এইচটিএমএল টেমপ্লেট সংকলন করা সম্ভব? plnkr.co/edit/vJHUCnsJB7cwNJr2cCwp?p= পূর্বরূপ এই প্লামকারে, আমি কীভাবে শেষ কলামে চিত্রটি সংকলন এবং প্রদর্শন করতে পারি?? কোন সাহায্য.?
কার্তিক

1
@ মোনেফ, আপনি ঠিক বলেছেন আমি কনসোল লগ চেক করিনি। আমি এনজিএফটারভিউআইনিট হুকের পরিবর্তে এনজিওএনইনাইটে উপাদান যুক্ত করার জন্য কোডটি সামঞ্জস্য করেছি, কারণ পূর্ববর্তীটির আগে ট্রিগার এবং পরিবর্তনটি সনাক্তকরণের পরে পরবর্তীটি তৈরি করা হয়েছে। ( Github.com/angular/angular/issues/10131 এবং অনুরূপ থ্রেড দেখুন ))
রেনি হামবুর্গ

1
ঝরঝরে ও সরল দেবের ব্রাউজারে পরিবেশন করার সময় প্রত্যাশার মতো কাজ করেছেন। কিন্তু এটিটি কি এওটি দিয়ে কাজ করে? সংকলনের পরে অ্যাপ্লিকেশনটি যখন PROD এ চালিত হয়, তখন উপাদান সংকলনের চেষ্টা করার মুহুর্তে আমি একটি "ত্রুটি: রানটাইম সংকলক লোড হয় না" get (বিটিডব্লিউ, আমি আয়নিক 3.5 ব্যবহার করছি)
মাইমো

52

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

আমি কি শেষ পর্যন্ত ব্যবহার করছে 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 এর জন্যও কাজ করে।


3
এটি Angular4 এর সাথে আমার পক্ষে দুর্দান্ত কাজ করেছে। আমার একমাত্র সামঞ্জস্যতাটি হ'ল গতিশীলভাবে তৈরি রানটাইম কম্পোনেন্টমোডিয়ুলের জন্য আমদানি মডিউলগুলি নির্দিষ্ট করতে সক্ষম হওয়া।
রাহুল প্যাটেল

8
এখানে কৌণিক কুইকস্টার্ট থেকে শুরু করে একটি চটজলদি উদাহরণ দেওয়া হয়েছে: এম্বেড.পিএলএনকিআর.কম
রাহুল প্যাটেল

5
এই সমাধানটি "এনজি বিল্ড - প্রোড" দিয়ে কাজ করে? দেখে মনে হচ্ছে সংকলক ক্লাস এবং এওটি এটিএম এ এক সাথে ফিট করে না।
পিয়েরে চাবারোচে

2
@ ওফিরস্টারন আমি এটিও আবিষ্কার করেছি যে অ্যাঙ্গুলার 5 এ অ্যাপ্রোচটি ভালভাবে কাজ করে তবে - প্রোড বিল্ড পতাকার সাথে নয়।
তাইকওনজয়ে

2
আমি এটি জিটকম্পিলার ফ্যাক্টরি ব্যবহার করে এবং কৌণিক 5 (5.2.8) দিয়ে পরীক্ষা করেছি - - প্রোড পতাকা ব্যবহার করে কাজ হয় না! কারো কাছে কি কোন সমাধান আছে? (বিটিডব্লিউ জিটকম্পাইল কারখানা
ফ্রাঙ্ক

20

2019 জুন উত্তর

বড় খবর! মনে হচ্ছে @ কৌণিক / সিডিকে প্যাকেজটির পোর্টালগুলির জন্য এখন প্রথম শ্রেণির সমর্থন রয়েছে !

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

পদক্ষেপ 1) আপনার আপডেট করুন AppModule

প্যাকেজ PortalModuleথেকে আমদানি করুন @angular/cdk/portalএবং আপনার গতিশীল উপাদান (গুলি) ভিতরে নিবন্ধ করুনentryComponents

@NgModule({
  declarations: [ ..., AppComponent, MyDynamicComponent, ... ]
  imports:      [ ..., PortalModule, ... ],
  entryComponents: [ ..., MyDynamicComponent, ... ]
})
export class AppModule { }

পদক্ষেপ 2. বিকল্প এ: আপনার যদি আপনার গতিশীল উপাদানগুলি থেকে ডেটা পাস এবং ইভেন্টগুলি গ্রহণ করার প্রয়োজন না হয় :

@Component({
  selector: 'my-app',
  template: `
    <button (click)="onClickAddChild()">Click to add child component</button>
    <ng-template [cdkPortalOutlet]="myPortal"></ng-template>
  `
})
export class AppComponent  {
  myPortal: ComponentPortal<any>;
  onClickAddChild() {
    this.myPortal = new ComponentPortal(MyDynamicComponent);
  }
}

@Component({
  selector: 'app-child',
  template: `<p>I am a child.</p>`
})
export class MyDynamicComponent{
}

এটি কর্মে দেখুন

পদক্ষেপ 2. বিকল্প বি: আপনার যদি আপনার গতিশীল উপাদানগুলির থেকে ডেটাগুলি পাস এবং ইভেন্টগুলি গ্রহণ করতে হয় তবে :

// A bit of boilerplate here. Recommend putting this function in a utils 
// file in order to keep your component code a little cleaner.
function createDomPortalHost(elRef: ElementRef, injector: Injector) {
  return new DomPortalHost(
    elRef.nativeElement,
    injector.get(ComponentFactoryResolver),
    injector.get(ApplicationRef),
    injector
  );
}

@Component({
  selector: 'my-app',
  template: `
    <button (click)="onClickAddChild()">Click to add random child component</button>
    <div #portalHost></div>
  `
})
export class AppComponent {

  portalHost: DomPortalHost;
  @ViewChild('portalHost') elRef: ElementRef;

  constructor(readonly injector: Injector) {
  }

  ngOnInit() {
    this.portalHost = createDomPortalHost(this.elRef, this.injector);
  }

  onClickAddChild() {
    const myPortal = new ComponentPortal(MyDynamicComponent);
    const componentRef = this.portalHost.attach(myPortal);
    setTimeout(() => componentRef.instance.myInput 
      = '> This is data passed from AppComponent <', 1000);
    // ... if we had an output called 'myOutput' in a child component, 
    // this is how we would receive events...
    // this.componentRef.instance.myOutput.subscribe(() => ...);
  }
}

@Component({
  selector: 'app-child',
  template: `<p>I am a child. <strong>{{myInput}}</strong></p>`
})
export class MyDynamicComponent {
  @Input() myInput = '';
}

এটি কর্মে দেখুন


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

2
@ Gi1ber7 আমি ঠিক জানি? কেন তাদের এত দিন লাগল?
স্টিফেন পল

1
চমৎকার পন্থা, তবে কী আপনি চাইল্ডকমম্পোনেন্টে প্যারামিটারগুলি পাস করবেন তা জানেন?
এপ্রু

1
এই আপনার প্রশ্নের উত্তর দিতে পারে @Snook stackoverflow.com/questions/47469844/...
স্টিফেন পল

4
@StephenPaul কিভাবে এই কী Portalপদ্ধতির থেকে পৃথক ngTemplateOutletএবং ngComponentOutlet? 🤔
গ্লেন মোহাম্মদ

18

আমি শিখেছি সমস্ত কিছুই একটি ফাইলে কম্প্যাক্ট করার সিদ্ধান্ত নিয়েছি । বিশেষত আরসি 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 {}`

10

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

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

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

এইচটিএমএল হিসাবে টেম্পলেট 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= পূর্বরূপ


3
সুতরাং, আপনি মডিউল 1, মডিউল 2, মডিউল 3 ঘোষণা করেছেন। এবং যদি আপনার অন্য একটি "গতিশীল" টেম্পলেট সামগ্রী প্রয়োজন হয়, আপনার একটি ডিকোমিশন (ফাইল) ফর্ম মওডল 4 (মডিউল 4.ts) তৈরি করতে হবে, তাই না? হ্যাঁ, এটি গতিশীল বলে মনে হয় না। এটা স্থির, তাই না? নাকি আমি কিছু মিস করছি?
রদিম কাহলর

উপরে "টেমপ্লেট 1" টি এইচটিএমএল এর স্ট্রিং, আপনি এটিতে যে কোনও কিছু রাখতে পারেন এবং আমরা এই গতিশীল টেম্পলেটটিকে ডাকি, কারণ এই প্রশ্নটি জিজ্ঞাসা করছে
লং ফিল্ড

6

কৌণিক x.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 এর সাথে অবজেক্টগুলি পাস করতে হবে এবং তার পরে এটি আবার বিশ্লেষণ করবে। এর থেকে ভাল সমাধান আমি খুঁজে পাচ্ছি না।


ইন্টারেস্টিং পন্থা, তবে আপনাকে আপনার tsconfig.json এ es2015 (সুতরাং IE11 এর জন্য কোনও সমর্থন নয়) করতে হবে, অন্যথায় এটি ব্যর্থ হবেdocument.createElement(tagName);
স্নুক

হাই, যেমন আপনি ইনপুটগুলি পরিচালনা করার একটি উপায় উল্লেখ করেছেন, তাই শিশু উপাদানগুলির আউটপুটগুলিও কি এইভাবে পরিচালনা করা যায়?
মোস্তাহসান

5

কেবল ব্যবহার করে কৌণিক 2 ফাইনাল সংস্করণে এই মীমাংসিত dynamicComponent থেকে নির্দেশ NG-গতিশীল

ব্যবহার:

<div *dynamicComponent="template; context: {text: text};"></div>

যেখানে টেম্পলেটটি আপনার গতিশীল টেম্পলেট এবং প্রসঙ্গটি এমন কোনও গতিশীল ডেটামোডেলে সেট করা যেতে পারে যা আপনি আপনার টেমপ্লেটটি আবদ্ধ করতে চান।


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

এটি এখনও কৌনিক 7+ এর জন্য প্রযোজ্য?
কার্লোস ই

4

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

আমি এই সমাধানটি নিয়েছি এবং এতে কিছুটা সময় নিয়ে কাজ করেছি এবং দ্রুত কিছুটা সীমাবদ্ধতার মধ্যে চলে এসেছি 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);
            });
    });

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

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


4

র‌্যাডমিনের দুর্দান্ত উত্তরের অনুসরণ করে, কৌণিক-ক্লিপ সংস্করণ 1.0.0-beta.22 এবং তদুর্ধের প্রত্যেকের জন্যই একটি সামান্য টুইটের প্রয়োজন।

COMPILER_PROVIDERSআর আমদানি করা যাবে না (বিশদগুলির জন্য কৌণিক-ক্লিপ গিটহাব দেখুন )।

কার্যসংক্রান্ত তাই আছে ব্যবহার না করার COMPILER_PROVIDERSএবং JitCompilerprovidersএ সব অধ্যায়, কিন্তু ব্যবহারের JitCompilerFactoryথেকে '@ কৌণিক / কম্পাইলার' পরিবর্তে টাইপ রচয়িতা শ্রেণীর ভিতরের ভালো:

private compiler: Compiler = new JitCompilerFactory([{useDebug: false, useJit: true}]).createCompiler();

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


1
এই পরামর্শের জন্য ধন্যবাদ, তবে, আমি "ডায়নামিকএইচটিএমএল মডেল" এর জন্য কোনও এনজিএমডিউল মেটাডেটা খুঁজে পাচ্ছি না "running আমার বাস্তবায়নের উপর ভিত্তি করে তৈরি stackoverflow.com/questions/40060498/...
Cybey

2
কেউ কি এওটি নমুনা নিয়ে জিটকমিলিটফ্যাক্টরিতে কাজ করছেন? আমার কাছে
@

এটি সম্ভবত সম্ভব বলে মনে হচ্ছে না। দয়া করে দেখুন github.com/angular/angular/issues/11780 , medium.com/@isaacplmann/... এবং stackoverflow.com/questions/42537138/...
সেবাস্টিয়ান

2

আমি নিজেও দেখার চেষ্টা করছি যে কীভাবে আমি আরসি 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>

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


1
এটি যাওয়ার একটি উপায় হবে .. switch/ যদি caseকয়েকটি সিদ্ধান্ত থাকে। তবে কল্পনা করুন যে উত্পন্ন টেমপ্লেটটি সত্যই বড় হতে পারে ... এবং প্রতিটি সত্তার জন্য পৃথক, সুরক্ষার দ্বারা পৃথক, সত্তার স্থিতি অনুসারে, প্রতিটি সম্পত্তির ধরণের (সংখ্যা, তারিখ, রেফারেন্স ... সম্পাদক) দ্বারা পৃথক হতে পারে ... এরকম ক্ষেত্রে, এটি এইচটিএমএল টেমপ্লেটে সমাধান ngSwitchকরে একটি বড়, খুব খুব বড় htmlফাইল তৈরি করবে ।
রাদিম কাহলার

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

1

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

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

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

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

ধন্যবাদ

বিজয়


0

এই বিশেষ ক্ষেত্রে দেখে মনে হচ্ছে গতিশীলভাবে একটি উপাদান তৈরি করার জন্য একটি নির্দেশিকা ব্যবহার করা আরও ভাল বিকল্প হবে। উদাহরণ:

এইচটিএমএলটিতে আপনি উপাদানটি তৈরি করতে চান

<ng-container dynamicComponentDirective [someConfig]="someConfig"></ng-container>

আমি নিম্নলিখিত পদ্ধতিতে নির্দেশের কাছে যেতে এবং ডিজাইন করব।

const components: {[type: string]: Type<YourConfig>} = {
    text : TextEditorComponent,
    numeric: NumericComponent,
    string: StringEditorComponent,
    date: DateComponent,
    ........
    .........
};

@Directive({
    selector: '[dynamicComponentDirective]'
})
export class DynamicComponentDirective implements YourConfig, OnChanges, OnInit {
    @Input() yourConfig: Define your config here //;
    component: ComponentRef<YourConfig>;

    constructor(
        private resolver: ComponentFactoryResolver,
        private container: ViewContainerRef
    ) {}

    ngOnChanges() {
        if (this.component) {
            this.component.instance.config = this.config;
            // config is your config, what evermeta data you want to pass to the component created.
        }
    }

    ngOnInit() {
        if (!components[this.config.type]) {
            const supportedTypes = Object.keys(components).join(', ');
            console.error(`Trying to use an unsupported type ${this.config.type} Supported types: ${supportedTypes}`);
        }

        const component = this.resolver.resolveComponentFactory<yourConfig>(components[this.config.type]);
        this.component = this.container.createComponent(component);
        this.component.instance.config = this.config;
    }
}

সুতরাং আপনার উপাদানগুলিতে পাঠ্য, স্ট্রিং, তারিখ, যাই হোক না কেন - ng-containerউপাদানটিতে আপনি যে কনফিগারটি এইচটিএমএল পাস করেছেন তা পাওয়া যাবে।

কনফিগারেশন, yourConfigএকই হতে পারে এবং আপনার মেটাডেটা সংজ্ঞায়িত করতে পারে।

আপনার কনফিগারেশন বা ইনপুট টাইপের উপর নির্ভর করে নির্দেশ অনুসারে কাজ করা উচিত এবং সমর্থিত প্রকারগুলি থেকে, এটি উপযুক্ত উপাদানটি রেন্ডার করবে। তা না হলে এটি একটি ত্রুটি লগ করবে।


-1

ওফির স্টার্নের উত্তরের শীর্ষে বিল্ডিং, এখানে একটি বৈকল্পিক যা কৌণিক 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;

  }

}

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

চিয়ার্স!

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.