उपयोगकर्ता-क्लिक किए गए घटकों के साथ गतिशील टैब


224

मैं एक टैब सिस्टम को सेटअप करने की कोशिश कर रहा हूं जो घटकों को खुद को पंजीकृत करने की अनुमति देता है (एक शीर्षक के साथ)। पहला टैब एक इनबॉक्स की तरह है, इसमें उपयोगकर्ताओं के लिए चुनने के लिए बहुत सारे कार्य / लिंक आइटम हैं, और इनमें से प्रत्येक क्लिक पर एक नए घटक को तत्काल करने में सक्षम होना चाहिए। क्रियाएँ / लिंक JSON से आती हैं।

तात्कालिक घटक तब एक नए टैब के रूप में खुद को पंजीकृत करेगा।

मुझे यकीन नहीं है कि क्या यह 'सर्वश्रेष्ठ' दृष्टिकोण है? अब तक, मैंने जो एकमात्र गाइड देखा है, वह स्टैटिक टैब के लिए है, जो मदद नहीं करता है।

अब तक, मुझे केवल टैब सेवा मिली है, जो मुख्य रूप से पूरे ऐप में बने रहने के लिए बूटस्ट्रैप्ड है। यह कुछ इस तरह दिखता है:

export interface ITab { title: string; }

@Injectable()
export class TabsService {
    private tabs = new Set<ITab>();

    addTab(title: string): ITab {
        let tab: ITab = { title };
        this.tabs.add(tab);
        return tab;
    }

    removeTab(tab: ITab) {
        this.tabs.delete(tab);
    }
}

प्रशन:

  1. मैं इनबॉक्स में एक डायनामिक सूची कैसे बना सकता हूं जो नए (अलग) टैब बनाता है? मुझे लगता है DynamicComponentBuilderकि इस्तेमाल किया जाएगा अनुमान लगा रहा हूँ ?
  2. इनबॉक्स से घटक कैसे बनाए जा सकते हैं (क्लिक करने पर) खुद को टैब के रूप में पंजीकृत करते हैं और दिखाए भी जाते हैं? मैं अनुमान लगा रहा हूं ng-content, लेकिन मुझे इसका उपयोग करने के तरीके के बारे में अधिक जानकारी नहीं मिल सकती है

EDIT: स्पष्ट करने का प्रयास।

मेल इनबॉक्स के रूप में इनबॉक्स को सोचें। आइटम JSON के रूप में प्राप्त होते हैं और यह कई आइटम प्रदर्शित करता है। एक आइटम पर क्लिक करने के बाद, उस आइटम एक्शन 'टाइप' के साथ एक नया टैब बनाया जाता है। प्रकार तब एक घटक है।

संपादित 2: छवि


यदि टैब में दिखाए गए घटक बिल्ड टाइम पर ज्ञात नहीं हैं, तो DCL सही तरीका है।
गुंटर ज़ोचबॉयर

7
मुझे आपकी आवश्यकता स्पष्ट रूप से समझ में नहीं आ रही है, इसलिए आपको बिना किसी काम के कोड / प्लंकर के बारे में कुछ भी बताना चाहिए। इसे देखें अगर यह आपको कहीं मदद कर सकता है plnkr.co/edit/Ud1x10xee7BmtUaSAA2R?p=preview (मुझे नहीं पता कि इसके प्रासंगिक हैं या नहीं)
micronyks

@micronyks मुझे लगता है कि आपको गलत लिंक मिला है
Cuel

नमस्ते! मैं वही करने की कोशिश कर रहा हूं जो आपने मांगा था। अब तक मैं डायनामिक कंटेंट के साथ टैब बनाने में कामयाब रहा लेकिन टैब बदले जाने पर मुझे कंपोनेंट स्टेट को बनाए रखने का कोई संतोषजनक तरीका नहीं मिला (लोड किए गए कंपोनेंट्स बहुत अलग हो सकते हैं)। आपने इसे कैसे प्रबंधित किया?
गिपिनि

जवाबों:


267

अपडेट करें

कोणीय 5 स्टैकब्लिट्ज उदाहरण

अपडेट करें

ngComponentOutlet 4.0.0-beta.3 में जोड़ा गया था

अपडेट करें

NgComponentOutletप्रगति में एक काम है जो कुछ इसी तरह करता है https://github.com/angular/angular/pull/11235

RC.7

प्लंकर उदाहरण RC.7

// Helper component to add dynamic components
@Component({
  selector: 'dcl-wrapper',
  template: `<div #target></div>`
})
export class DclWrapper {
  @ViewChild('target', {read: ViewContainerRef}) target: ViewContainerRef;
  @Input() type: Type<Component>;
  cmpRef: ComponentRef<Component>;
  private isViewInitialized:boolean = false;

  constructor(private componentFactoryResolver: ComponentFactoryResolver, private compiler: Compiler) {}

  updateComponent() {
    if(!this.isViewInitialized) {
      return;
    }
    if(this.cmpRef) {
      // when the `type` input changes we destroy a previously 
      // created component before creating the new one
      this.cmpRef.destroy();
    }

    let factory = this.componentFactoryResolver.resolveComponentFactory(this.type);
    this.cmpRef = this.target.createComponent(factory)
    // to access the created instance use
    // this.compRef.instance.someProperty = 'someValue';
    // this.compRef.instance.someOutput.subscribe(val => doSomething());
  }

  ngOnChanges() {
    this.updateComponent();
  }

  ngAfterViewInit() {
    this.isViewInitialized = true;
    this.updateComponent();  
  }

  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }    
  }
}

उदाहरण का उपयोग करें

// Use dcl-wrapper component
@Component({
  selector: 'my-tabs',
  template: `
  <h2>Tabs</h2>
  <div *ngFor="let tab of tabs">
    <dcl-wrapper [type]="tab"></dcl-wrapper>
  </div>
`
})
export class Tabs {
  @Input() tabs;
}
@Component({
  selector: 'my-app',
  template: `
  <h2>Hello {{name}}</h2>
  <my-tabs [tabs]="types"></my-tabs>
`
})
export class App {
  // The list of components to create tabs from
  types = [C3, C1, C2, C3, C3, C1, C1];
}
@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App, DclWrapper, Tabs, C1, C2, C3],
  entryComponents: [C1, C2, C3],
  bootstrap: [ App ]
})
export class AppModule {}

Angular.io डायनामिक घटक लोडर भी देखें

पुराने संस्करण xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

यह Angular2 RC.5 में फिर से बदल गया

मैं नीचे दिए गए उदाहरण को अपडेट करूंगा लेकिन यह छुट्टी से पहले अंतिम दिन है।

यह प्लंकर उदाहरण दर्शाता है कि RC.5 में घटकों को गतिशील रूप से कैसे बनाया जाए

अपडेट - ViewContainerRef .createComponent () का उपयोग करें

क्योंकि DynamicComponentLoaderपदावनत है, दृष्टिकोण को फिर से अद्यतन करने की आवश्यकता है।

@Component({
  selector: 'dcl-wrapper',
  template: `<div #target></div>`
})
export class DclWrapper {
  @ViewChild('target', {read: ViewContainerRef}) target;
  @Input() type;
  cmpRef:ComponentRef;
  private isViewInitialized:boolean = false;

  constructor(private resolver: ComponentResolver) {}

  updateComponent() {
    if(!this.isViewInitialized) {
      return;
    }
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }
   this.resolver.resolveComponent(this.type).then((factory:ComponentFactory<any>) => {
      this.cmpRef = this.target.createComponent(factory)
      // to access the created instance use
      // this.compRef.instance.someProperty = 'someValue';
      // this.compRef.instance.someOutput.subscribe(val => doSomething());
    });
  }

  ngOnChanges() {
    this.updateComponent();
  }

  ngAfterViewInit() {
    this.isViewInitialized = true;
    this.updateComponent();  
  }

  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }    
  }
}

Plunker उदाहरण RC.4
प्लंकर उदाहरण Beta.17

अद्यतन - loadNextToLocation का उपयोग करें

export class DclWrapper {
  @ViewChild('target', {read: ViewContainerRef}) target;
  @Input() type;
  cmpRef:ComponentRef;
  private isViewInitialized:boolean = false;

  constructor(private dcl:DynamicComponentLoader) {}

  updateComponent() {
    // should be executed every time `type` changes but not before `ngAfterViewInit()` was called 
    // to have `target` initialized
    if(!this.isViewInitialized) {
      return;
    }
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }
    this.dcl.loadNextToLocation(this.type, this.target).then((cmpRef) => {
      this.cmpRef = cmpRef;
    });
  }

  ngOnChanges() {
    this.updateComponent();
  }

  ngAfterViewInit() {
    this.isViewInitialized = true;
    this.updateComponent();  
  }

  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }    
  }
}

प्लंकर उदाहरण beta.17

मूल

आपके प्रश्न से पूरी तरह से निश्चित नहीं है कि आपकी आवश्यकताएं क्या हैं, लेकिन मुझे लगता है कि यह वही करना चाहिए जो आप चाहते हैं।

Tabsघटक पारित किया प्रकार की एक सरणी हो जाता है और यह सरणी में प्रत्येक आइटम के लिए "टैब" बनाता है।

@Component({
  selector: 'dcl-wrapper',
  template: `<div #target></div>`
})
export class DclWrapper {
  constructor(private elRef:ElementRef, private dcl:DynamicComponentLoader) {}
  @Input() type;

  ngOnChanges() {
    if(this.cmpRef) {
      this.cmpRef.dispose();
    }
    this.dcl.loadIntoLocation(this.type, this.elRef, 'target').then((cmpRef) => {
      this.cmpRef = cmpRef;
    });
  }
}

@Component({
  selector: 'c1',
  template: `<h2>c1</h2>`

})
export class C1 {
}

@Component({
  selector: 'c2',
  template: `<h2>c2</h2>`

})
export class C2 {
}

@Component({
  selector: 'c3',
  template: `<h2>c3</h2>`

})
export class C3 {
}

@Component({
  selector: 'my-tabs',
  directives: [DclWrapper],
  template: `
  <h2>Tabs</h2>
  <div *ngFor="let tab of tabs">
    <dcl-wrapper [type]="tab"></dcl-wrapper>
  </div>
`
})
export class Tabs {
  @Input() tabs;
}


@Component({
  selector: 'my-app',
  directives: [Tabs]
  template: `
  <h2>Hello {{name}}</h2>
  <my-tabs [tabs]="types"></my-tabs>
`
})
export class App {
  types = [C3, C1, C2, C3, C3, C1, C1];
}

प्लंकर उदाहरण Beta.15 (आपके प्लंकर पर आधारित नहीं)

डेटा को पास करने का एक तरीका भी है जिसे गतिशील रूप से बनाए गए घटक की तरह someDataपास किया जा सकता है (जैसे पास करने की आवश्यकता होगी type)

    this.dcl.loadIntoLocation(this.type, this.elRef, 'target').then((cmpRef) => {
  cmpRef.instance.someProperty = someData;
  this.cmpRef = cmpRef;
});

साझा सेवाओं के साथ निर्भरता इंजेक्शन का उपयोग करने के लिए कुछ समर्थन भी है।

अधिक जानकारी के लिए https://angular.io/docs/ts/latest/cookbook/dynamic-component-loader.html देखें


1
निश्चित रूप से, आपको DclWrapperइसे वास्तविक उदाहरण बनाने के लिए बस घटकों को प्राप्त करने की आवश्यकता है ।
गुंटर ज़ोचबॉयर

1
@ जोसेफ आप उपयोग करने के ViewContainerRefबजाय इंजेक्ट कर सकते हैं ViewChild, फिर <dcl-wrapper>खुद ही लक्ष्य बन जाता है। तत्वों को लक्ष्य के भाई-बहनों के रूप में जोड़ा जाता है और इसलिए वे <dcl-wrapper>इस तरह से बाहर होंगे ।
गुंटर ज़ोचौएर

1
प्रतिस्थापित करने का समर्थन नहीं किया गया है। आप टेम्पलेट ''(खाली स्ट्रिंग) को बदल सकते हैं और निर्माणकर्ता को बदल सकते हैं constructor(private target:ViewContainerRef) {}, फिर गतिशील रूप से जोड़े गए घटक भाई-बहन बन सकते हैं<dcl-wrapper>
गुंटर ज़ोचबॉयर

1
मैं RC4 का उपयोग कर रहा हूं और उदाहरण काफी उपयोगी था। केवल एक चीज जो मैं उल्लेख करना चाहता था, वह यह है कि मुझे इस कोड को ठीक से काम करने के लिए नीचे दिए गए कोड को जोड़ना होगा। ChampRef.changeDetectorRef.detectChanges ();
राजीव

4
जब मुझे ngAfterViewInit का उपयोग करते समय डायनामिक घटक में एक और डायनामिक घटक मिला, तो मुझे एक त्रुटि मिली। इसके बजाय ngAontContentInit में बदला गया और अब यह नेस्टेड डायनेमिक घटकों के साथ काम कर रहा है
Abris

20

मैं टिप्पणियों के लिए पर्याप्त शांत नहीं हूं। मैंने आरसी 2 के लिए काम करने के लिए स्वीकृत उत्तर से प्लंकर को ठीक कर दिया। कुछ भी नहीं फैंसी, सीडीएन के लिंक सिर्फ टूटे हुए थे।

'@angular/core': {
  main: 'bundles/core.umd.js',
  defaultExtension: 'js'
},
'@angular/compiler': {
  main: 'bundles/compiler.umd.js',
  defaultExtension: 'js'
},
'@angular/common': {
  main: 'bundles/common.umd.js',
  defaultExtension: 'js'
},
'@angular/platform-browser-dynamic': {
  main: 'bundles/platform-browser-dynamic.umd.js',
  defaultExtension: 'js'
},
'@angular/platform-browser': {
  main: 'bundles/platform-browser.umd.js',
  defaultExtension: 'js'
},

https://plnkr.co/edit/kVJvI1vkzrLZJeRFsZuv?p=preview


16

वहाँ घटक (rc5 संगत) ng2- चरणों का उपयोग Compilerकरने के लिए तैयार है जो एक साथ सब कुछ तारों के लिए कंटेनर और सेवा को इंजेक्ट करने के लिए घटक का उपयोग करता है (डेटा सिंक)

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

import { StepsService } from './ng2-steps';

@Directive({
  selector:'[ng2-step]'
})
export class StepDirective implements OnInit{

  @Input('content') content:any;
  @Input('index') index:string;
  public instance;

  constructor(
    private compiler:Compiler,
    private viewContainerRef:ViewContainerRef,
    private sds:StepsService
  ){}

  ngOnInit(){
    //Magic!
    this.compiler.compileComponentAsync(this.content).then((cmpFactory)=>{
      const injector = this.viewContainerRef.injector;
      this.viewContainerRef.createComponent(cmpFactory, 0,  injector);
    });
  }

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