कोणीय 2 में $ संकलन के बराबर


134

मैं मैन्युअल रूप से कुछ HTML युक्त निर्देशों को संकलित करना चाहता हूं। $compileकोणीय 2 में समतुल्य क्या है ?

उदाहरण के लिए, कोणीय 1 में, मैं गतिशील रूप से HTML के एक टुकड़े को संकलित कर सकता हूं और इसे DOM में जोड़ सकता हूं:

var e = angular.element('<div directive></div>');
element.append(e);
$compile(e)($scope);

8
अधिकांश ये उत्तर (अब 1 पदावनत उत्तर को छोड़कर) कोणीय 1 $ संकलन के समतुल्य नहीं हैं। $ संकलन एक HTML स्ट्रिंग लेता है और इसमें निहित घटकों और अभिव्यक्तियों को संकलित करता है। ये उत्तर बस पूर्व-परिभाषित घटकों को बनाते हैं (जो अभी तक त्वरित नहीं हैं) गतिशील रूप से और CANNOT एक स्ट्रिंग तर्क ले सकते हैं। यह एक ही बात नहीं है। क्या किसी को इस सवाल का असली जवाब पता है?
danday74


कोणीय 4 कॉम्पोनेन्टफैक्टरी के साथ आया है। जो कि कोणीय 1.0 में $ संकलित के बराबर है। मेरा उत्तर देखें stackoverflow.com/questions/34784778/…
EZ

1
@ danday74 - मैं मानता हूं कि इनमें से कोई भी उत्तर मनमाने ढंग से HTML टेम्पलेट्स को संकलित करने की क्षमता प्रदान नहीं करता है, इसके बजाय वे सिर्फ पहले से मौजूद घटकों के एक सेट से चयन करते हैं। मुझे यहां वास्तविक उत्तर मिला, जो कम से कम 8 में काम करता है: stackoverflow.com/questions/61137899/… । एक उत्तर देखें, जो एक काम करने वाला StackBlitz प्रदान करता है जो एक मनमाना रन-टाइम जनरेट किया गया HTML टेम्पलेट संकलित करता है।
EbenH

जवाबों:


132

कोणीय 2.3.0 (2016-12-07)

सभी विवरण जांचने के लिए:

कार्रवाई में यह देखने के लिए:

प्रिंसिपल:

1) बनाएँ खाका
2) घटक
3 बनाएँ) मॉड्यूल
4 बनाएँ ) संकलन मॉड्यूल
5) बनाएँ (और कैश) घटक
6) इसका एक उदाहरण बनाने के लिए लक्ष्य का उपयोग करें

एक त्वरित अवलोकन कैसे एक घटक बनाने के लिए

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

NgModule में घटक को इंजेक्ट करने का तरीका

createComponentModule (componentType: any) {
  @NgModule({
    imports: [
      PartsModule, // there are 'text-editor', 'string-editor'...
    ],
    declarations: [
      componentType
    ],
  })
  class RuntimeComponentModule
  {
  }
  // a module for just this Type
  return RuntimeComponentModule;
}

एक कोड स्निपेट कैसे बनाया जाता है ComponentFactory (और इसे कैश करें)

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

एक कोड स्निपेट उपरोक्त परिणाम का उपयोग करने का तरीका है

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

सभी विवरणों के साथ पूर्ण विवरण यहां पढ़ें , या कार्यशील उदाहरण देखें

OBSOLETE - कोणीय 2.0 RC5 संबंधित (RC5 केवल)

पिछले RC संस्करणों के लिए पिछले समाधान देखने के लिए, कृपया इस पोस्ट के इतिहास के माध्यम से खोजें


2
बहुत बहुत धन्यवाद, मैं काम कर रहे उदाहरण के लिए देख रहा था ComponentFactoryऔर ViewContainerRefअब पदावनत डायनामिककंपोनेंटलॉडर को बदलना चाहता हूं।
आंद्रे लोकर

1
@maxou यह सूचकांक में लो-डैश संदर्भ है। अभी उस संदर्भ को जोड़ें और सभी काम करेंगे
Radim Köhler

62
क्या वास्तव में यह मुश्किल है? मैं बस कुछ ऐसा करने में सक्षम हुआ करता था: $compile($element.contents())($scope.$new());और अब कोड की सैकड़ों लाइनें हैं, जो कि NgModule निर्माण के साथ पूरी होती है ... यह इस तरह की चीज है जो मुझे NG2 को स्पष्ट करने और कुछ बेहतर करने के लिए आगे बढ़ना चाहती है।
करवापल्लो

2
JitCompilerयदि आपके उदाहरण Compilerसे काम हो सकता है तो उपयोग करने का क्या फायदा है @angular/core? plnkr.co/edit/UxgkiT?p=preview
yurzui

4
ओह माय गॉड, एक छोटे से तत्व को संकलित करने के लिए मुझे कोड की कितनी लाइनें लिखनी चाहिए। मुझे अच्छी तरह से समझ नहीं आया
Mr_Perfect

35

नोट: जैसा कि @BennyBottema एक टिप्पणी में उल्लेख करता है, डायनामिककंपोनेंटलॉडर को अब हटा दिया गया है, इसलिए यह उत्तर है।


Angular2 के पास कोई $ संकलन नहीं है । आप DynamicComoponentLoaderअपने कोड को गतिशील रूप से संकलित करने के लिए ES6 कक्षाओं के साथ उपयोग और हैक कर सकते हैं (यह प्लंक देखें ):

import {Component, DynamicComponentLoader, ElementRef, OnInit} from 'angular2/core'

function compileToComponent(template, directives) {
  @Component({ 
    selector: 'fake', 
    template , directives
  })
  class FakeComponent {};
  return FakeComponent;
}

@Component({
  selector: 'hello',
  template: '<h1>Hello, Angular!</h1>'
})
class Hello {}

@Component({
  selector: 'my-app',
  template: '<div #container></div>',
})
export class App implements OnInit {
  constructor(
    private loader: DynamicComponentLoader, 
    private elementRef: ElementRef,
  ) {}

  ngOnInit() {} {
    const someDynamicHtml = `<hello></hello><h2>${Date.now()}</h2>`;

    this.loader.loadIntoLocation(
      compileToComponent(someDynamicHtml, [Hello])
      this.elementRef,
      'container'
    );
  }
}

लेकिन यह केवल तब तक काम करेगा जब तक html parser कोणीय 2 कोर के अंदर न हो।


बहुत बढ़िया चाल! लेकिन अगर मेरे डायनामिक घटक में कुछ इनपुट हैं तो क्या डायनेमिक डेटा को भी बांधना संभव है?
यूजीन ग्लुहटोरेंको

2
मेरे स्वयं के प्रश्न का उत्तर देना: संकलन कार्य के लिए डेटा पास करना संभव है। यहाँ प्लंक plnkr.co/edit/dK6l7jiWt535jOw1Htct?p=preview
Eugene Gluhotorenko

यह समाधान केवल बीटा -० के साथ काम कर रहा है। बीटा 1 से 15 तक उदाहरण कोड एक त्रुटि देता है। त्रुटि: तत्व [वस्तु वस्तु] पर कोई घटक निर्देश नहीं है
निकोलस फ़ॉर्नी

13
चूंकि rc1 डायनामिककंपोनेंटलॉडर अपदस्थ हो गया है
बेनी बोटेमा

1
@BennyBottema के बाद DynamicComponentLoaderसे पदावनत किया जाता है, हम एक ही प्रकार की चीज़ कोणीय 2 में कैसे करते हैं? कहो कि मेरे पास एक संवाद है और मैं एक नए घटक को गतिशील रूप से लोड करना चाहता हूं क्योंकि यह सामग्री है
ल्यूक टी ओ'ब्रायन

16

कोणीय संस्करण मैंने इस्तेमाल किया है - कोणीय 4.2.0

कोणीय 4 घटक समय पर घटकों को लोड करने के लिए ComponentFactoryResolver के साथ आया है। यह $ संकलन का एक समान कार्यान्वयन है Angular 1.0 में जो आपकी आवश्यकता को पूरा करता है

इस नीचे उदाहरण में मैं एक डैशबोर्ड TileComponent में गतिशील रूप से ImageWidget घटक लोड कर रहा हूं

एक घटक को लोड करने के लिए आपको एक निर्देश की आवश्यकता होती है जिसे आप एनजी-टेम्पलेट पर लागू कर सकते हैं जो गतिशील घटक को रखने में मदद करेगा

WidgetHostDirective

 import { Directive, ViewContainerRef } from '@angular/core';

    @Directive({
      selector: '[widget-host]',
    })
    export class DashboardTileWidgetHostDirective {
      constructor(public viewContainerRef: ViewContainerRef) { 


      }
    }

यह निर्देश गतिशील रूप से जोड़े गए घटक को होस्ट करने वाले तत्व के दृश्य कंटेनर तक पहुंच प्राप्त करने के लिए ViewContainerRef को इंजेक्ट करता है।

DashboardTileComponent (डायनामिक घटक रेंडर करने के लिए स्थान धारक घटक)

यह घटक एक इनपुट को स्वीकार करता है जो मूल घटक से आ रहा है या आप अपने कार्यान्वयन के आधार पर अपनी सेवा से लोड कर सकते हैं। यह घटक रनटाइम पर घटकों को हल करने के लिए प्रमुख भूमिका निभा रहा है। इस पद्धति में आप रेंडरकंपोनेंट () नाम की एक विधि भी देख सकते हैं जो अंततः घटक नाम को एक सेवा से लोड करती है और ComponentFactoryResolver के साथ हल करती है और अंत में गतिशील घटक को डेटा सेट करती है।

import { Component, Input, OnInit, AfterViewInit, ViewChild, ComponentFactoryResolver, OnDestroy } from '@angular/core';
import { DashboardTileWidgetHostDirective } from './DashbardWidgetHost.Directive';
import { TileModel } from './Tile.Model';
import { WidgetComponentService } from "./WidgetComponent.Service";


@Component({
    selector: 'dashboard-tile',
    templateUrl: 'app/tile/DashboardTile.Template.html'
})

export class DashboardTileComponent implements OnInit {
    @Input() tile: any;
    @ViewChild(DashboardTileWidgetHostDirective) widgetHost: DashboardTileWidgetHostDirective;
    constructor(private _componentFactoryResolver: ComponentFactoryResolver,private widgetComponentService:WidgetComponentService) {

    }

    ngOnInit() {

    }
    ngAfterViewInit() {
        this.renderComponents();
    }
    renderComponents() {
        let component=this.widgetComponentService.getComponent(this.tile.componentName);
        let componentFactory = this._componentFactoryResolver.resolveComponentFactory(component);
        let viewContainerRef = this.widgetHost.viewContainerRef;
        let componentRef = viewContainerRef.createComponent(componentFactory);
        (<TileModel>componentRef.instance).data = this.tile;

    }
}

DashboardTileComponent.html

 <div class="col-md-2 col-lg-2 col-sm-2 col-default-margin col-default">        
                        <ng-template widget-host></ng-template>

          </div>

WidgetComponentService

यह सभी घटकों को पंजीकृत करने के लिए एक सेवा कारखाना है जिसे आप गतिशील रूप से हल करना चाहते हैं

import { Injectable }           from '@angular/core';
import { ImageTextWidgetComponent } from "../templates/ImageTextWidget.Component";
@Injectable()
export class WidgetComponentService {
  getComponent(componentName:string) {
          if(componentName==="ImageTextWidgetComponent"){
              return ImageTextWidgetComponent
          }
  }
}

ImageTextWidgetComponent (घटक हम रनटाइम पर लोड कर रहे हैं)

import { Component, OnInit, Input } from '@angular/core';


@Component({
    selector: 'dashboard-imagetextwidget',
    templateUrl: 'app/templates/ImageTextWidget.html'
})

export class ImageTextWidgetComponent implements OnInit {
     @Input() data: any;
    constructor() { }

    ngOnInit() { }
}

अंत में प्रविष्टि के रूप में अपने App मॉड्यूल में इस ImageTextWidgetComponent को जोड़ें

@NgModule({
    imports: [BrowserModule],
    providers: [WidgetComponentService],
    declarations: [
        MainApplicationComponent,
        DashboardHostComponent,
        DashboardGroupComponent,
        DashboardTileComponent,
        DashboardTileWidgetHostDirective,
        ImageTextWidgetComponent
        ],
    exports: [],
    entryComponents: [ImageTextWidgetComponent],
    bootstrap: [MainApplicationComponent]
})
export class DashboardModule {
    constructor() {

    }
}

TileModel

 export interface TileModel {
      data: any;
    }

मेरे ब्लॉग से ओरिजिनल रेफरेंस

आधिकारिक दस्तावेज

नमूना स्रोत कोड डाउनलोड करें


1
आप के बारे में बताना भूल गए entryComponents। इसके बिना आपका समाधान काम नहीं करेगा
yurzui

ComponentFactoryResolver कोणीय 2 में था। और मुझे लगता है कि यह $ संकलन के बराबर नहीं है
yurzui

@ युरज़ुई लेकिन यह $ संकलित अधिकार की आवश्यकता को पूरा करता है ??
कोड-ईज़ी

@yurzui मैं $ संकलन का उपयोग करके उसी तरह के कार्यान्वयन का उपयोग किया गया था। जब हम मॉड्यूल से प्रवेश घटकों को हटाते हैं तो यह एक त्रुटि फेंक देगा ImageTextWidgetComponent लोड नहीं है। लेकिन आवेदन अभी भी काम करता है
कोड-ईज़ी

1
@BecarioSenior यदि आप किसी भी मॉडल वर्ग में नहीं आते हैं, तो यह डिफ़ॉल्ट रूप से गतिशील होगा। इस उदाहरण में संपत्ति डेटा का प्रकार कोई भी है, जिसका अर्थ है कि आप किसी भी डेटा को इनपुट के रूप में गतिशील घटक को पास कर सकते हैं। यह आपके कोड को अधिक पठनीयता देता है।
कोड-ईज़ी

9

इस npm पैकेज ने मेरे लिए यह आसान बना दिया: https://www.npmjs.com/package/ngx-dynamic-template

उपयोग:

<ng-template dynamic-template
             [template]="'some value:{{param1}}, and some component <lazy-component></lazy-component>'"
             [context]="{param1:'value1'}"
             [extraModules]="[someDynamicModule]"></ng-template>

3

एक घटक का एक उदाहरण बनाने के लिए और इसे अपने DOM में संलग्न करने के लिए आप निम्नलिखित स्क्रिप्ट का उपयोग कर सकते हैं और कोणीय रिक में काम करना चाहिए :

html टेम्पलेट:

<div>
  <div id="container"></div>
  <button (click)="viewMeteo()">Meteo</button>
  <button (click)="viewStats()">Stats</button>
</div>

लोडर घटक

import { Component, DynamicComponentLoader, ElementRef, Injector } from '@angular/core';
import { WidgetMeteoComponent } from './widget-meteo';
import { WidgetStatComponent } from './widget-stat';

@Component({
  moduleId: module.id,
  selector: 'widget-loader',
  templateUrl: 'widget-loader.html',
})
export class WidgetLoaderComponent  {

  constructor( elementRef: ElementRef,
               public dcl:DynamicComponentLoader,
               public injector: Injector) { }

  viewMeteo() {
    this.dcl.loadAsRoot(WidgetMeteoComponent, '#container', this.injector);
  }

  viewStats() {
    this.dcl.loadAsRoot(WidgetStatComponent, '#container', this.injector);
  }

}

1
डायनामिककम्पोनेंटलॉडर अब और नहीं है: '(उसके बाद पदावनत हो गया था, वहाँ ComponentResolver था। और अब वहाँ ComponentFactoryResolver ( blog.rangle.io/dynamically-creator-compenders-with-angular-2 )
11mb

3

कोणीय टाइपस्क्रिप्ट / ES6 (कोणीय 2+)

AOT + JIT के साथ एक साथ काम करता है।

मैंने इसे यहां उपयोग करने का तरीका बनाया: https://github.com/patrikx3/angular-compile

npm install p3x-angular-compile

घटक: एक संदर्भ और कुछ html डेटा होना चाहिए ...

एचटीएमएल:

<div [p3x-compile]="data" [p3x-compile-context]="ctx">loading ...</div>

1
यह स्पष्ट नहीं है कि 'कोणीय टाइपस्क्रिप्ट' शीर्षक का क्या अर्थ है। क्या समाधान ES5 और ES6 के लिए बेकार है? यह इस पैकेज के प्रोग्रामेटिक उपयोग का उदाहरण प्रदान करने के लिए सहायक होगा, जो एक प्रत्यक्ष समकक्ष है $compile(...)($scope)। रेपो रीडमे में भी इस पर कुछ नहीं है।
एस्टस फ्लास्क

2

आप घटक को देख सकते हैं, जो सरल गतिशील कोणीय घटकों को संकलित करने की अनुमति देता है https://www.npmjs.com/package/@codehint-ng/html-compiler


यह इस पुस्तकालय का उपयोग कर काम किया! :) सिफारिश के लिए धन्यवाद।
हाउससेम चेलीगू

0

मुझे पता है कि यह मुद्दा पुराना है, लेकिन मैंने यह जानने में हफ्तों का समय बिताया कि इस काम को एओटी सक्षम कैसे बनाया जाए। मैं एक ऑब्जेक्ट को संकलित करने में सक्षम था लेकिन मौजूदा घटकों को निष्पादित करने में सक्षम नहीं था। खैर मैंने आखिरकार चातुर्य बदलने का फैसला किया, क्योंकि मैं एक कस्टम टेम्पलेट को निष्पादित करने के लिए कोड को बहुत अधिक नहीं देख रहा था। मेरा विचार html को जोड़ना था जो कोई भी कर सकता है और मौजूदा कारखानों में लूप कर सकता है। ऐसा करने में मैं तत्व / विशेषता / आदि की खोज कर सकता हूं। नाम और उस HTMLElement पर घटक निष्पादित करें। मैं इसे काम कर पाने में सक्षम था और मुझे लगा कि मुझे किसी और को बचाने के लिए इसे साझा करना चाहिए जो मैंने उस पर बर्बाद किया।

@Component({
    selector: "compile",
    template: "",
    inputs: ["html"]
})
export class CompileHtmlComponent implements OnDestroy {
    constructor(
        private content: ViewContainerRef,
        private injector: Injector,
        private ngModRef: NgModuleRef<any>
    ) { }

    ngOnDestroy() {
        this.DestroyComponents();
    }

    private _ComponentRefCollection: any[] = null;
    private _Html: string;

    get Html(): string {
        return this._Html;
    }
    @Input("html") set Html(val: string) {
        // recompile when the html value is set
        this._Html = (val || "") + "";
        this.TemplateHTMLCompile(this._Html);
    }

    private DestroyComponents() { // we need to remove the components we compiled
        if (this._ComponentRefCollection) {
            this._ComponentRefCollection.forEach((c) => {
                c.destroy();
            });
        }
        this._ComponentRefCollection = new Array();
    }

    private TemplateHTMLCompile(html) {
        this.DestroyComponents();
        this.content.element.nativeElement.innerHTML = html;
        var ref = this.content.element.nativeElement;
        var factories = (this.ngModRef.componentFactoryResolver as any)._factories;
        // here we loop though the factories, find the element based on the selector
        factories.forEach((comp: ComponentFactory<unknown>) => {
            var list = ref.querySelectorAll(comp.selector);
            list.forEach((item) => {
                var parent = item.parentNode;
                var next = item.nextSibling;
                var ngContentNodes: any[][] = new Array(); // this is for the viewchild/viewchildren of this object

                comp.ngContentSelectors.forEach((sel) => {
                    var ngContentList: any[] = new Array();

                    if (sel == "*") // all children;
                    {
                        item.childNodes.forEach((c) => {
                            ngContentList.push(c);
                        });
                    }
                    else {
                        var selList = item.querySelectorAll(sel);

                        selList.forEach((l) => {
                            ngContentList.push(l);
                        });
                    }

                    ngContentNodes.push(ngContentList);
                });
                // here is where we compile the factory based on the node we have
                let component = comp.create(this.injector, ngContentNodes, item, this.ngModRef);

                this._ComponentRefCollection.push(component); // save for our destroy call
                // we need to move the newly compiled element, as it was appended to this components html
                if (next) parent.insertBefore(component.location.nativeElement, next);
                else parent.appendChild(component.location.nativeElement);

                component.hostView.detectChanges(); // tell the component to detectchanges
            });
        });
    }
}

-5

यदि आप html कोड उपयोग निर्देश इंजेक्षन करना चाहते हैं

<div [innerHtml]="htmlVar"></div>

यदि आप पूरे घटक को किसी स्थान पर लोड करना चाहते हैं, तो DynamicsComponentLoader का उपयोग करें:

https://angular.io/docs/ts/latest/api/core/DynamicComponentLoader-class.html


2
मैं एक स्ट्रिंग के रूप में HTML के एक टुकड़े को इंजेक्ट करना चाहता हूं और इसे एक घटक संकलक को पास करता हूं, और फिर उस घटक को मेरे डोम में जोड़ देता हूं। क्या आप इस बात का उदाहरण दे सकते हैं कि आपका कोई भी समाधान कैसे काम कर सकता है?
पिक्सल

3
इनरएचएचटीएमएल का उपयोग htmlVar
Juanín
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.