TimTheEnchanter
TimTheEnchanter

Reputation: 3671

Angular 2: Conditional Output Property Binding

Is it possible to conditionally bind to an output property? Something like this: <my-Component (myOutputProp)="funcThatReturnsTrueOrFalse()? func1() : func2()"></my-component>

I've tried the above example, as well as <my-Component (myOutputProp)="funcThatReturnsFunc1OrFunc2()></my-component>.

I've looked around and come to the realization that you can't dynamically change bindings after the fact, can't access EventListeners from nativeElement, and seen some indications that you could do this with regular event bindings, although I couldn't get those to work either.

Thanks.

UPDATE

My output property is defined like this:

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

UPDATE 2

For reasons beyond my control, I can't just fire one event and branch within that based on true/false. Primarily because in one situation, a false value from my ternary expression evaluation will not bind anything to the output property, and I need to be able to detect that within my child component (via myOutputProp.observers.length)

Upvotes: 0

Views: 3586

Answers (1)

Roddy of the Frozen Peas
Roddy of the Frozen Peas

Reputation: 15180

You can use the EventEmitter to emit based on your boolean value. Just push the appropriate value via the emit(...) method.

Here's a simple example including two components. One component is a button, which emits a String value that changes when you click the button. The other component is consuming that event and displaying it. You can find a demo here: https://stackblitz.com/edit/angular-4natth

Here's the first component, which is a simple button. Note that clicking the button sets a boolean flag. This flag then determines which string is emitted by the event emitter.

@Component({
  selector: 'my-example',
  template: '<button mat-raised-button (click)="doThings()">Click me!</button>'
})
export class ExampleComponent {

  @Output()
  status: EventEmitter<string> = new EventEmitter();

  flag = false;

  doThings() {
    this.flag = !this.flag; // toggle the boolean flag
    this.status.emit(this.getValue()); // push the value
  }

  private getValue() {
    if(this.flag) {
      return "Truthy!";
    }
    return "Falsy!";
  }
}

The second component is consuming and the values being emitted from (status):

@Component({
  selector: 'my-container',
  template: '<my-example (status)="updateStatus($event)">loading...</my-example><p>Current status: {{status}}</p>'
})
export class ContainerComponent {
  status: string = "Not set yet - click the button!";

  updateStatus(value: string) {
    this.status = value;
  }
}

Whenever you click the button, the EventEmitter.emit(...) method is called, pushing the appropriate value. On the other end, the event is consumed using (status)="updateStatus($event)", where in this case $event is of type string because I've declared the EventEmitter to be emitting a string. I could easily have also been emitting a boolean value and have the updateStatus method instead do different things based on the emitted value.


So, say for example you have this in your Component:

@Output()
myOutputProp: EventEmitter<boolean> = new EventEmitter();

You could then do something like this:

<my-Component (myOutputProp)="someFunc($event)"></my-component>

And define your someFunc like this:

someFunc(emittedValue: boolean) {
  emittedValue ? func1() : func2();
}

Or, let's say you need the output of your event emitter to be some sort of value that you need preserved rather than a boolean. You could still declare your component the same:

<my-Component (myOutputProp)="someFunc($event)"></my-component>

And define your someFunc like this:

someFunc(emittedValue: any) { 
  funcThatReturnsTrueOrFalse() ? func1(emittedValue) : func2(emittedValue);
}

So while you can't directly bind the ternary to the event emitter, you can instead bind something static which turns around and invokes the ternary itself.

Upvotes: 2

Related Questions