Giter Club home page Giter Club logo

Comments (13)

gund avatar gund commented on May 28, 2024 1

@narendrapandey999 I had a look into your plunkr.

First of all there were some errors not related at all to my library (some angular-cdk errors) that I had to fix.

Finally I upgraded my library from v1.1.0 (which is quite outdated) to v3.1.1 and took advantage of (ndcDynamicCreated) output that allowed me to get a reference to created component and then execute it's method.

One important thing to note is that when (ndcDynamicCreated) output emits outputs are not yet bound to your component so you should wait one JS tick to then trigger your emit (via setTimeout).

Here's the fixed version: https://stackblitz.com/edit/angular-with-ng-dynamic-component-k4olqc?file=app%2Fspawner.component.ts

EDIT: I also added content projection, and in your spawner component I grab it like this <div #content><ng-content></ng-content></div> and then I can pass content via content to [ndcDynamicContent]="[[content]]"
Be aware that the div element will also go inside with projected content. It is required to have in order to properly get the reference to it.

from ng-dynamic-component.

gund avatar gund commented on May 28, 2024

We to pass the content you need to specify where that content will go in the component (in your case in comp-trial and in dyn-comp1).

You can do that by placing <ng-content></ng-content>.
This technique is called Content Projection.

But since you have to pass that content from your comp-trial you can try to create a local template variable on that content, and then forward it to dynamic component:

comp-trial:

<!-- Make sure this piece is hidden from user -->
<ng-content #content></ng-content>
<ndc-dynamic 
		[ndcDynamicComponent]="dynamicComponent"
		[ndcDynamicInputs]="inputs"
		[ndcDynamicOutputs]="outputs"
                [ndcDynamicInputs]="[[content]]"
	  >
	  </ndc-dynamic>

dyn-comp1:

<div>{{ title }}</div>
<div class="content"><ng-content></ng-content></div>

And btw, your types in TrialComponent of inputs and outputs properties are incorrect, instead of Array<any> they should be objects ({[key: string]: any}).

Cheers.

from ng-dynamic-component.

locinus avatar locinus commented on May 28, 2024

Thanks for a quick reply !

Nice trick to create the local variable on content. My content does appear in the added not-yet-hidden ng-content node of the Trial component (comp-trial).

However, adapting my code that way (and considering you meant to write:

[ndcDynamicContent]="[[content]]"

), I get the following error:

TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.

It seems to be 'undefined': ideas?

from ng-dynamic-component.

gund avatar gund commented on May 28, 2024

I suspect that the local variable might be of type TemplateRef. In that case you can try to access property nativeElement to pass into ndcDynamicContent.

Also in comp-trial you can try to query-select ng-content by that local template variable name and console log it on AfterContentInit hook to see exactly what you get.

This was always tricky part to forward real content that way and I never saw an example in official Angular docs how to do it although they have exactly the same support on NgComponentOutlet directive...

from ng-dynamic-component.

locinus avatar locinus commented on May 28, 2024

Ok, so after trying few things, it seems that a ng-content node is not a valid node to pass to ndcDynamicContent. So I wrapped it in another proper node, and it works fine now.

My working code, for the archives:

Trial Component

@Component({
	selector: 'comp-trial',
	template: '
	  <div style="display:none">
		<span #mycontent>
		  <ng-content></ng-content>
		</span>
	  </div>      
	  <ndc-dynamic 
		[ndcDynamicComponent]="dynamicComponent"
		[ndcDynamicInputs]="inputs"
		[ndcDynamicOutputs]="outputs"
		[ndcDynamicContent]="[[mycontent]]"
	  >
	  </ndc-dynamic>
	'
})
export class TrialComponent {
  dynamicComponent; // the component to insert dynamically (management of this var is not developed here)
  @Input() inputs: Array<any>;
  @Input() outputs: Array<any>;
}

One of the dynamic component

@Component({
  selector: 'dyn-comp1',
  template: '
	<div>{{ title }}</div>
	<div class="content"> <ng-content></ng-content> </div>
  '
})
export class ExpandablePanel1Component extends ExpandablePanel {
   @Input() title;
   @Output() click;
}

Using the trial component

...
<comp-trial 
  [inputs]="{ title:'...' }"
  [outputs]="{ click: myOnClickHandler }"
>
	This is some content for the dynamic components
</comp-trial>
...

Thanks for the help, and the library !

from ng-dynamic-component.

gund avatar gund commented on May 28, 2024

Great!
Thanks for sharing the solution, very helpful 👍

from ng-dynamic-component.

narendrapandey999 avatar narendrapandey999 commented on May 28, 2024

Hello,
In my case Trial Component (dummy-spawner) is being called from another component and in their I am setting data like below -

<dummy-gridster-item [item]="{cols: 1, rows: 1, y: 0, x: 5}">
     <dummy-spawner [input_component]= "component" [received_input_data]= "input" (output_data)='changereceived($event)' fxFlex="30%">
     <dummy-header #CardHeader>
      <dummy-title>{{header}}</dummy-title>
       </dummy-header>
       <dummy-content>
         <section fxLayout="column"  fxLayoutAlign="center center">
           <dummy-metric dummyMetricScale="xxl" align="center">
             {{content}}
           <dummy-metric-detail>users</dummy-metric-detail>
           </dummy-metric>
         </section>
       </dummy-content>
       <dummy-footer fxLayoutAlign="start" >
         {{footer}}
       </dummy-footer>
     </dummy-spawner>
   </dummy-gridster-item>

Here dummy-spawner is Trial component. Below is my dynamic component -

<mat-card >
  <mat-card-header >
    <ng-content select="dummy-header"></ng-content>
  </mat-card-header>
  <mat-card-content>
    <ng-content select="dummy-content"></ng-content>
  </mat-card-content>
  <mat-card-footer>
    <ng-content select="dummy-footer"></ng-content>
  </mat-card-footer>
 
</mat-card>

So i am have received value from dynamic component emit event and have saved them in header, footer and content of dummy-gridster-item component. I am trying to add these values directly using "{{header}}". But it doesn't work.

I have used above approach and added the class manually in above ndc-dynamic imports. But i am trying to avoid that. Is there any other way so that I could maintain the styling as well making less changes caller component(dummy-gridster-item component)

from ng-dynamic-component.

gund avatar gund commented on May 28, 2024

Please provide live example of your problem on stackblitz.com then I might have a look.

from ng-dynamic-component.

narendrapandey999 avatar narendrapandey999 commented on May 28, 2024

Hello Gund, Below is the stackblitz url.

https://stackblitz.com/edit/angular-with-ng-dynamic-component-c6vexd

It is currently having some import issue hence not working correctly.
In it, I am passing data from my app component to a spawner component. Spawner component spawn the component received and call its HelloTwComponent.execute() method. It emits back data to output() method of spawner component and then again spawner component emits back to app component changereceived() method.
I am trying to use this received data and component to set data in app.component.html => Card-header.
Cad-header content is input to HelloTwoComponent. I am trying to inject value for HelloTwoComponent through appComponent's html. As HelloTwoComponent have more component embedded to it and expects ng-content input of those components, i am following such approach.

from ng-dynamic-component.

narendrapandey999 avatar narendrapandey999 commented on May 28, 2024

Hello @gund, thanks for the working code.
I am still facing issue with spawning as the rendered data from child component is being set in my code but it still doesn't get spawned in web page. Could there be a possible object initialisation issue as my app_component have a ngAfterViewChecked() call (I have to add this check to get recent modifications from child component) and ndcDynamicCreated.instacne.execute() gets called quite later.
In my code, i was calling execute() function of child through OnInit() block. I have replaced that part with ndcDynamicCreated.instacne.execute() and have removed that code from OnInit call.

To debug this issue, i tried adding hard coded value in n app_component.html.
<card-title>123</card-title>
It surely gets reflected in plunkr but not in actual code. any thoughts what else could be missing

from ng-dynamic-component.

narendrapandey999 avatar narendrapandey999 commented on May 28, 2024

Also, is it mandate to use ndcDynamicCreated or if we can invoke the underlying method of child component through other means. For eg, making part of ngOnInit()

from ng-dynamic-component.

narendrapandey999 avatar narendrapandey999 commented on May 28, 2024

Ok. After lot of hit n trial , it worked. I was missing <div> tag in my projected content (as you have mentioned in :( ). So i enclosed my child component html with <div> tag and it worked. It didn't took the styling as required , but it seems specific to our project. Thanks again :)

from ng-dynamic-component.

narendrapandey999 avatar narendrapandey999 commented on May 28, 2024

Hello @gund , I am using below code in my spawner template -

div #content><ng-content></ng-content></div>

<ndc-dynamic [ndcDynamicComponent]="component"
             [ndcDynamicInputs]="dynamicInput"
             [ndcDynamicOutputs]="dynamicOutput"
              [ndcDynamicContent]="[[content]]"
             (ndcDynamicCreated)="componentCreated($event)"
             ></ndc-dynamic>

Consider, i am using this template to pass a dynamic component. But the values are not getting set at correct position in dynamic component template. Values are simply getting entered in above the actual template. They are positioned as per I have placed div #content><ng-content></ng-content></div>. If it is before <ndc-dynamic> block, it adds all data above my template and if its below <ndc-dynamic> block then data is placed below my dynamic template.

For eg - if div tag is paced ahead


{{header}}
{{content}}
{{footer}}
<mat-card >
  <mat-card-header >
    <ng-content select="dummy-header"></ng-content>
  </mat-card-header>
  <mat-card-content>
    <ng-content select="dummy-content"></ng-content>
  </mat-card-content>
  <mat-card-footer>
    <ng-content select="dummy-footer"></ng-content>
  </mat-card-footer>
 
</mat-card>

Can't we really add data from spawner component to dynamic component in my above example? Is there some sort of restriction??

from ng-dynamic-component.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.