Home > database >  What is the best way to get an event output from a third level child component in a parent component
What is the best way to get an event output from a third level child component in a parent component

Time:12-29

I have a parent component that contains a child component, which in turn contains another child component. The third level child component emits an event that I would like to capture in the parent component. What is the best way to do this?

I have tried using the @Output() decorator and EventEmitter in the third level child component, but I'm not sure how to access the event in the parent component. I have also considered using a service to communicate between the components, but I'm not sure if that is the most efficient or correct solution.

Of course I could just create another @Output on the second child to be referenced to the parent, but I am thinking is there a better way to get the event output from the third level child component in the parent component?

CodePudding user response:

You can use the javascript event delegation, see the comments in the code. Here you can listen the click event of the children in the third level by the event delegation listening the container that your item is in.

const selectedElementText = document.querySelector('#selectedElement');
const grandfather = document.querySelector('#grandfather');
let currentSelected;

// HERE YOU LISTEN THE GRANDFATHER(FIST LEVEL) AND GO INTO YOUR CHILDREN 
grandfather.addEventListener('click', (e)=>{
  e.stopPropagation();
  setBorderSelectionStyle(e.target);
  const level = getLevel(e.target);

  //HERE DEPENDES OF YOUR CHILDREN CLASS YOU DO SOMETHING
  showLevelTextOnTop(level);
});

const setBorderSelectionStyle = (target)=>{
    if(currentSelected){
    currentSelected.classList.remove('border-box');
  }
  currentSelected = target;
  target.classList.add('border-box');
}

const getLevel = (target)=> target.classList[1];
const showLevelTextOnTop = (level)=>{
    switch(level){
    case 'first-level':
        selectedElement.innerText = 'First level selected';
      break;
    case 'second-level':
        selectedElement.innerText = 'Second level selected';
      break;
    case 'third-level':
        selectedElement.innerText = 'Third level selected';
      break;
    default:
            selectedElement.innerText = '';
  }
};
.box{
  width: fit-content;
  padding: 20px;
  border: 1px solid grey;
  font-size: 11px;
}

.third-level{
  width: 30px;
  height: 30px;
}

.border-box{
  border: 2px dashed blue;
}
<h1>Event Delegation Example</h1>
<p id="selectedElement">
  No Level Selected
</p>

<div id="grandfather" >
  <div id="parent-1" >
    <div id="parent-1-child1" >
    </div>
  </div>
  
  <div id="parent-2" >
    <div id="parent-2-child-1" >
    </div>
  </div>
</div>

CodePudding user response:

Why do not use a singleton service to handle all g-parent/parent/child interaction ?

example: parentComponent.ts

export class ParentComponent implements OnInit {
  constructor(
    private _childService: ChildService
  ) {
    this._childService.childSelected$.subscribe((child) => {
      this.child = child;
    }
  }
}

childComponent.ts

export class ChildComponent implements OnInit {
  constructor(
    private _childService: ChildService
  ) { }

  ngOnInit() {
    this._childService.selectChild('childId');
  }
}

childService.service.ts

export class childService {
  childClicked$: BehaviorSubject<string> = new BehaviorSubject('');

  constructor(
    private _http: HttpClient,
    private _storageService: StorageService,
    private toastr: ToastrService
  ) { }

  selectChild(child) {
    this.childClicked$.next(child);
  }
}

inject the service in the parent / grandparent component, listen to the clicked behaviorsubject and trigger any method you want then.

inject the service in child component and update the behaviorsubject on trigger.

This is a reduced example don't forget to clean your subscriptions on component destroy.

Hope it will helps !

  • Related