Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Consolidating Two Directives into a Single One

Suppose one has two predefined directives dir1 and dir2 ( which are provided by a 3rd party API that one has no control over). Let's say these can be applies to an html element as follows:

<div dir1="red" [dir2]="123">... My Content ...</div>

I have found myself applying the above the directives with the exact same binding values in several places in my code. Rather than repeat myself, I would like to create my own custom directive, call it myDir, that I could apply like this:

<div MyDir >... My Content ...</div>

This should be exactly the same as applying dir1 and dir2 as in the prior example above i.e. it will have the values "red" and 123 hard coded within it's class.

I have tried setting host bindings as in the following plunker example, but this doesn't work..

One idea I have is if only typescript had multiple inheritance, then I would simply write the MyDir class an extension of Dir1 and Dir2..

My question is how do I go about writing the custom directive (MyDir) to achieve the intended use?

Kindly Assist, Thanks You!

https://plnkr.co/edit/W20Wvew326qsGfPU5H6v

like image 687
Somo S. Avatar asked Jan 12 '17 16:01

Somo S.


People also ask

Can we use two custom directive in a single HTML element?

This error occurs when multiple directives are applied to the same DOM element, and processing them would result in a collision or an unsupported configuration. To resolve this issue remove one of the directives which is causing the collision.

Can we use multiple directives in angular?

You can not use two structural directives on the same element. You need to wrap your element in another one. It's advised to use ng-container since it wont be rendered in DOM.

What are structural directives?

Structural directives are directives which change the DOM layout by adding and removing DOM elements. Angular provides a set of built-in structural directives (such as NgIf , NgForOf , NgSwitch and others) which are commonly used in all Angular projects. For more information see Built-in directives.

How do I use multiple directives in angular 2?

To apply multiple directives we'll have to either (a) expand the sugared syntax, (b) nest template tags or use the <ng-content> tag. It is important to note, that like the ng-template elemement, ng-container elements are not rendered to the DOM, but rather their child(ren) are/is.


1 Answers

Update: Still not possible in May 2020. It is on the Angular Team's feature backlog. Follow progress here https://github.com/angular/angular/issues/8785

(TL;DR. For my hack soln, See Plunker here)

The following is what ended up being my solutions for the problem, as presented above. Note that this is not the most general solution; In other scenarios, it's adaptability will depend largely one what the public API of the directives involved looks like. It should work well where the directives to be combined have atleast ElementRef as one of the injection dependencies like:

constructor(private elRef: ElementRef, /*...*/) { /*...*/ }

This may well be the case if the directives are responsible for changing the styling of an element.

What I did was, I simply created two new Dir1/Dir2 objects passing in the MyDir's ElementRef as context for Dir1/Dir2 like so:

// inside MyDir constructor
this.d1 = new Dir1(this.elRef,  /*...*/);
this.d2 = new Dir2(this.elRef,  /*...*/);

Then I set the public properties (@Input bindings) of d1/d2 to values I need them to permanently be (to avoid repeating myself):

//inside MyDir constructor
this.d1.dir1 = "red";
this.d2.dir2 = 123;

Next, all I had to try and do was match up the public methods d1/d2 with MyDir by invoking the former's methods inside the corresponding method(s) of the latter, e.g.

ngAfterContentInit() {
  this.d1.ngAfterContentInit();
  this.d2.ngAfterContentInit();
}

Here is the plunker with this all pieced together https://plnkr.co/edit/TCagW8vOPrqSiOT9Oztf

like image 186
Somo S. Avatar answered Sep 18 '22 16:09

Somo S.