1

What I want to accomplish is to show all elements from an array. This array contains various types of components (yes, components), and all these components extends from an abstract class.

Here's my code:

Abstract Class Plugin:

export abstract class Plugin {
constructor() { }
}

Watch Component:

@Component({
selector: 'watch',
template: `
    {{clock | async | date:'medium'}} 
 `
})

export class WatchCmpt extends Plugin {
    clock = Observable.interval(1000).map(() => new Date())
    constructor() {
      super();
    }
}

Demo Component:

@Component({
selector: 'demo',
template: `
    <h1>Hello {{name}}</h1>
`
})

export class DemoCmpt extends Plugin {
     name: string = "Jose";
     constructor() {
        super();
     }
}

I'm using this code in my view to display it in my html file:

<? *ngFor="let target of targetList; let x = index">{{target}} </?>

What should I use in the <?> ?

targetList is an array like this: [demo, watch]

EDIT:

@Component({
    selector: 'dndPanel',
    templateUrl: 'dragNdropPanel.cmpt.html'
 })

export class DragNDropPanelCmpt {
   @ViewChild(DemoCmpt) demo1: DemoCmpt;
   @ViewChild(WatchCmpt) watch: WatchCmpt;

   constructor() {
   }

   targetList: Plugin[] = [
      this.demo1,
      this.watch,
   ];

   addTo($event: any) {
      this.targetList.push($event.dragData);
  }
}

This is the complete HTML:

   div class="col-sm-6">
    <div class="panel panel-info" dnd-sortable-container [sortableData]="targetList">
        <div class="panel-heading">Target List</div>
        <div class="panel-body" dnd-droppable (onDropSuccess)="addTo($event)" [dropZones]="['source-dropZone']">
            <ul class="list-group">
                <li *ngFor="let target of targetList; let x = index" class="list-group-item" dnd-sortable [sortableIndex]="x" [dragEnabled]="true">
                    {{target}}
                </li>
            </ul>
        </div>
    </div>
</div>
Roman C
  • 49,761
  • 33
  • 66
  • 176
Oscar_sgc
  • 340
  • 5
  • 20

3 Answers3

2

The issue is that you are trying to use concrete elements inside of your generic list. A generic list can only operate on its elements as of the API defined by the parent abstract class.

In other words, you can only assume the list contains objects of type Plugin. Type plugin is not a component so you cannot assume children are components. Angular does not have a great way to extend components, so your idea of making OO components does not work out.

Example:

What if I created another class that extends Plugin, but is not a @Component? How would the list render a non-component?

Joel Jeske
  • 1,618
  • 14
  • 17
  • That is correct and i understand that, right now i want to render the components, is there something that i can use to do that? – Oscar_sgc Aug 04 '17 at 19:40
  • Well your example is a fixed set of components. If that is really the case, I would simply hard-code the components you want to render right in the template. – Joel Jeske Aug 04 '17 at 19:55
  • At the time it is, but i want to create a dashboard with drag and drop components, so i need to put any kind of components inside the array and render them – Oscar_sgc Aug 04 '17 at 19:58
  • That makes sense. I would look at either one of these guides: [Dynamic component loader](https://angular.io/guide/dynamic-component-loader) or the much simpler [NgSwitch](https://angular.io/api/common/NgSwitch). The switch would allow you to detect the component type and render the component desired in the template – Joel Jeske Aug 04 '17 at 19:59
1

I could achieve what I needed using ComponentFactory. I found an interesting article in this website, it does exactly what I wanted: Render many different components in a single view from a list without hardcoding with ngSwitch or other more complex(to me) tasks.

I appreciate all the answers and comments

Oscar_sgc
  • 340
  • 5
  • 20
  • Great find. Didn't realize that. Are you able to configure the component (passing \@input values and receiving \@output events)? – Joel Jeske Aug 11 '17 at 16:39
  • @JoelJeske now I'm trying to make that work, if i can do it, or if i find something i'll let you know – Oscar_sgc Aug 11 '17 at 16:47
  • @JoelJeske I made it... you can use [this answer](https://stackoverflow.com/a/39280103/2979805) it worked perfectly to me – Oscar_sgc Aug 12 '17 at 19:49
0

You should use in the <?> the router outlet.

Router outlet is used to rote the componet output to the main container.

You use the outlet as the tag added to the template superclass.

<router-outlet></router-outlet>

If you ever read about a Router it will tell you that

The Angular Router enables navigation from one view to the next as users perform application tasks.

The problem with the design components are object oriented and doesn't have a common override interface. Thus the coding performs a bit harder especially bumping one component over another with the card layout.

Roman C
  • 49,761
  • 33
  • 66
  • 176