Jared Clemence
Jared Clemence

Reputation: 1065

How do I access the component that is modified by the directive in Angular2?

Let us assume a hypothetical situation. You and I have a component (named AComponent) identified by the selector a-component, and a directive identified by the selector [is-modified].

In another component's definition file, we use the following template that combines our component and our directive, which modifies the component:

<a-component is-modified></a-component>

The documentation for a attribute Directive indicates that the constructor gives the directive access to the ElementRef, but there is no link from ElementRef to the Component parent.

export class IsModifiedDirective
{
    constructor( elementReference : ElementRef )
    {
        console.log( elementReference );

        //no connection appears to exist between elementReference and the component
        //also: ElementRef has security risks, so it should be avoided.

        debugger;
    }
}

I tried using injection to inject the necessary component and changed the ElementRef to a ComponentRef<AComponent>; this gave the error that no provider is specified for ComponentRef. I then tried to inject the component AComponent, but that generated errors as well.

The documentation clearly indicates that "Attribute directives—change the appearance or behavior of an element, component, or another directive.", but I do not see how the Directive obtains access to the component that it modifies.

Can anyone provide assistance?

Upvotes: 2

Views: 97

Answers (1)

Jared Clemence
Jared Clemence

Reputation: 1065

The answer was found here: Component Interactions

The secret to communication is to inject a service into the constructors. I extended the Component and the Directive to use the same service:

//The Component Definition (Psuedocode)
@Component(
{
   ...,
   providers: [ AService ],
   ...
}
)
export class AComponent
{
    constructor( commonService : AService )
    {
         let comp : AComponent = this;
         commonService.serviceAnnouncement$.subscribe(
             (msg)=>{
                  //msg can be anything we like, in my specific instance,
                  //I passed a reference to the directive instance

                  comp.doSomethingWithMsg( msg );
             }
         );
    }

}

--

//The Directive Definition (Psuedocode)
@Directive(...)
export class IsModifiedDirective
{
    constructor( commonService : AService )
    {
         commonService.announceSomething( this );
    }
}

--

//The Service Definition (Psuedocode)
import { Subject } from 'rxjs/Subject';
@Injectable(...)
export class AService
{
    private source = new Subject<MsgType>();

    serviceAnnouncement$ = this.source.toObservable();

    announceSomething( msg : MsgType )
    {
         this.source.next( msg );
    }
}

The above classes exist in their own files. The imports and other code are mostly left out to avoid cluttering the display. They key is that the objects can pass instances of themselves to other objects listening to the shared service. The documentation suggests that the providers attribute of the @Component decorator might establish a unique provider shared by that component and its descendants; I have not tested this implied feature.

If you are reading this, it is important to note that the communication used above, where the directive passes itself to the component, only works for my specific case, and the message that is passed between your objects should be specific to your implementation.

Upvotes: 1

Related Questions