Snedden27
Snedden27

Reputation: 1930

sharing event driven variable across component in angular 2

I have a component which has a data table which I filter using a pipe,

The way I trigger and sent new argument to the pipe is on input-event on a input tag , I capture the input in 'targetInput' variable,

The above setup works, here is how it looks like:

        <tr >
            <td  *ngFor="let column of currentView.columns">
                <div *ngIf="column.label">
                    <input placeholder="{{column.label}}" id="{{column._devName}}" type="text"
                           (input)="targetInput = {targetValue:$event.target.value,targetId:$event.target.id,currentFilterMap:currentFilterMap}">
                </div>
            </td>
        </tr>

        <ng-container *ngFor="let task of (currentView.tasks | countryPipe:targetInput); let i=index">
            <tr class="worktask" (click)="setCurrentTask($event, task)" (dblclick)="openWindowNewTab(getOpenTaskURL(task, currentView.process))"
                id="workspace_table_wo_{{ task.workOrderId }}_task_{{ task.taskId }}"
                [class.table-active]="isSelected(task)">
                <td *ngFor="let column of currentView.columns">{{task[column.devName]}}</td>
            </tr>

Now I decide , that I want a separate component for the input tag , so I split the html and make a parent-child setup and pass the shared variable using @Input decorator,

This is how the new setup looks , Parent html:

    <tr >
        <td  *ngFor="let column of currentView.columns">
            <filterTagBox [taskCol] = "column" [currentFilterMap] = "currentFilterMap"></filterTagBox>
        </td>
    </tr>
    <ng-container *ngFor="let task of (currentView.tasks | countryPipe:targetInput); let i=index">
        <tr class="worktask" (click)="setCurrentTask($event, task)" (dblclick)="openWindowNewTab(getOpenTaskURL(task, currentView.process))"
            id="workspace_table_wo_{{ task.workOrderId }}_task_{{ task.taskId }}"
            [class.table-active]="isSelected(task)">
            <td *ngFor="let column of currentView.columns">{{task[column.devName]}}</td>
        </tr>

Now I can't seem to pass the targetInput from the child component back to the parent on the input event, Not sure if this is the way I should implement this or if there is a better way.

Upvotes: 0

Views: 137

Answers (3)

Snedden27
Snedden27

Reputation: 1930

Thanks for the answers , I did figure out how I could do this ,and although I found using behaviour service interesting I decided to use a output variable to sent data form the child component to the parent which would ultimatedly sent to the pipe,

Here is what I did :

Child component HTML:

                <div *ngIf="taskCol.label">
                    <div id="{{taskCol._devName}}_tagBox"></div>
                    <input placeholder="{{taskCol.label}}" id="{{taskCol._devName}}" type="text"
             <!-- Call childComponent.onInput passing event parameters -->              

   (input)="onInput({targetValue:$event.target.value,targetId:$event.target.id})"> 
                </div>

Child component.ts :

@Component({
  selector: 'filterTagBox',
  template: require('./filterTagBox.component.html')
})
export class FilterTagBox{

  private colValues:string[];
  public containsQueries:boolean;
  private regex:RegExp;
  @Input() public taskCol:TaskColumn;                          

  @Output() onItemInput = new EventEmitter<any>();   // bound event to the parent component

  // constructor and other hidden methods...

  onInput(targetInput : any){
    this.onItemInput.emit(targetInput);            //trigger  onItemInput event on inputBox input 
  }


}

Parent component html :

<tr >
                <td  *ngFor="let column of currentView.columns">
                     <!-- Catch custom onItemInput event which was triggered in the child -->
                    <filterTagBox (onItemInput)="filterBoxPipeData = {targetValue:$event.targetValue,targetId:$event.targetId,currentFilterMap:currentFilterMap}"  [taskCol] = "column" ></filterTagBox>
                </td>
            </tr>

            <!--sent the data retrieve from the input i.e filterBoxPipeData to the pipe i.e tagBoxFilterPipe along with data to be filtered i.e currentView.task -->
            <ng-container *ngFor="let task of (currentView.tasks | tagBoxFilterPipe:filterBoxPipeData); let i=index">
                <tr> 
                <!--hidden html -->
                </tr>

Upvotes: 0

Emre Piskin
Emre Piskin

Reputation: 284

I use BehaviorSubject to notify any component (the parent in your situation) that subscribes it. It's a special type of observables. A message service can do it for you. Define a message model (you can even use a simple string if you prefer) and create a message service:

import {Observable, BehaviorSubject} from 'rxjs/Rx'; // 
import {Message} from "../../models/message";        // Your model

... inside your message service class:

private _newMessage = new BehaviorSubject<Message>(new Message);
getMessage = this._currentUser.asObservable();
sendMessage(message: Message) { this._newMessage.next(message) }

In a component (e.g. in a parent), you can subscribe getMessage subject like this:

this.messageService.getMessage.subscribe(
message => {
    // a message received, do whatever you want
    if (message == "so important message")
      this.list = newList;
    // ... so on
});

This way, multiple components can subscribe to this BehaviorSubject, and any trigger in any component/service that uses sendMessage method can change these subscribed components immediately. For you, that can be a child component:

... you successfully made something in your
... child component, now use the trigger:

this.messageService.sendMessage(new Message("so important message", foo, bar));

Upvotes: 1

CharanRoot
CharanRoot

Reputation: 6325

I think in your case parent is Parent html and child is filterTagBox. if you want transfer value from parent to child you need use @input

if you want transfer value from child to parent you need use EventEmitter and @Output

more info. https://angular.io/docs/ts/latest/cookbook/component-communication.html

Upvotes: 1

Related Questions