DaveC426913
DaveC426913

Reputation: 2046

Angular 2: emitter listener between components

I am making a 'skip to content' link. The link is in app.component and the content is in login.component, along with the target.

I've tried several methods, none of which worked out. So now I'm trying emitter/listener:

app.component (emitter):

import { Component, Output, EventEmitter} from '@angular/core';

export class AppComponent {

    @Output() skipToCtrl: EventEmitter<any> = new EventEmitter();

    skipLink() {
        this.skipToCtrl.emit();
    }
}

<a href="#content-start" (click)="skipLink()">Skip to main content</a>

login.component (listener):

<input type="text" #firstControl name="username" />

Don't know how login can subscribe to the event from within login. I keep finding articles that say not to do it How to subscribe to an event on a service in Angular2? but no articles that describe how to do it.

Upvotes: 5

Views: 12926

Answers (4)

afsarkhan10182
afsarkhan10182

Reputation: 2212

100% Working!!!! It's basically a patch using Javascript:

Make a hidden input element in which component(app.component in your case) you need to call

<input type="hidden" id="getdata" (click)="Mydata();">

Here Mydata will be function in app.component

And call/Click this from other component(Login) using javascript:

document.getElementById('getdata').click();

Upvotes: -1

chairmanmow
chairmanmow

Reputation: 650

You're putting the event emitter in the wrong component for one. Event emitter is for child -> parent communication. So you'd probably want to put that in your login-component, if you want it to do anything.

login.component.ts

 export class LoginComponent {
     @Output() skipToCtrl: EventEmitter<any> = new EventEmitter();
     emitSkipEvent(): void {
         this.skipToCtrl.emit(true);
     }
  }

app.component.html

 <login-component (skipToCtrl)="skipLink()">

There's a problem with my solution though, that event will never get emitted because I never call loginComponent.emitSkipEvent, I don't think EventEmitter behavior is what you're looking for as you want to pass data from the parent to the loginComponent. You probably want to put an @Input parameter on your login component and implement onChanges to handle the behavior. BETTER ANSWER :

 import {OnChanges} from '@angular/core'
 export class LoginComponent implements OnChanges {
     @Input() skipToCtrl: boolean;
     ngOnChanges(){
         if(skipToCtrl){
             // handle login component behavior changes here. Looks like you want to focus on the input
             document.querySelector('input').focus();
         }
      }
}

Then in your app.component.ts you'd create a boolean variable to toggle

 linkClicked:boolean;

Then in your app.component.html you can change the click behavior and bind the linkClicked to your login component's skipToCtrl boolean :

<a href="#content-start" (click)="linkClicked = true">Skip to main content</a>
<login-component [skipToCtrl]='linkClicked'>

Now when you click the link it will get passed down to the login component, and the OnChanges logic will fire.

Upvotes: 0

Reactgular
Reactgular

Reputation: 54731

Event emitters are used to add output into the templates. Using the round brackets () for binding to the event.

When you create a component:

@Component({...})
public export FooComponent {
   @Output() name: EventEmitter = new EventEmitter<string>();
}

The above component now has an attribute that can be used with the () brackets in another template.

In another template:

 <foo (name)="// code here //"></foo>

When the event is emitted (by calling this.name.emit("value")) the above "code here" expression is executed by Angular. The emit function takes a single argument which is passed to the expression as a $event variable.

To have another component receive these events is to use the expression in that other component's template.

Let's create a Bar component

@Component({...})
export class BarComponent {
    public setName(value:string) {
        console.log(value); // will output "chicken"
    }
}

The above component has this template:

<foo (name)="setName($event)"></foo>

Now in the Foo component we emit a value.

@Component({...})
public export FooComponent implements OnInit {
   @Output() name: EventEmitter = new EventEmitter<string>();

   public ngOnInit() {
       this.name.emit("chicken");
   }
}

This creates one-way communication from the Foo component to the Bar component via the template expressions.

Upvotes: 6

Janier
Janier

Reputation: 4402

in the login.component, u can write

<input type="text" #firstControl (skipToCtrl)="callsomemethod($event)" name="username" />

Upvotes: 0

Related Questions