0
votes

I'm new to Angular 2+ and I'm facing a trivial situation that I don't seem to find a way out.

I have a parent component (parent.component.html) that holds a list of components (item.component.html) rendered through an iteration, like this:

parent.component.html

<child-item-component *ngFor="let date of shift?.dates" [shift]="shift"
    [dragEnabled]="dragEnabled"></child-item-component>

child-item.component.html

<li [contextMenuTrigger]="contextMenuData">
  <ng-template contextMenuHost></ng-template>
</li>

Each child component has a <li> element with a [contextMenuTrigger] directive attached to it. This directive contains logic to inject a dynamic component, which is a tooltip with different actions, irrelevant to the matter.

When a user clicks on the element holding the directive (<li>), the dynamic component is rendered.

After trying to emit an event through @Output() from the directive to the component without success, I ended up using Subjects through a bidirectional service to communicate between parents and children when a click has happened.

REQUIREMENT

I need to set [dragEnabled] on <child-item-component> to false.

THE PROBLEM

I was able to pass that boolean to the parent, but I need to take action on the specific parent item ONLY, the one that has just been injected with the dynamic component, so that this specific item is not draggable while the tooltip is open, but the rest still are. Basically, I need a way to provide context to the Subject so that I can identify from which of the [contextMenuTrigger] directives inside their respective <child-item-component> was triggered the event, otherwise, all of the item components receive the event and all of them turn [dragEnabled] to false at the same time without any chance to distinguish them.

I've been looking around and I don't see anyone having the same situation over here, so I'm wondering if I'm doing something wrong.

  • Which would be the best practice to achieve that on a Subject?
  • Is there a way to detect the origin of the event by using the params sent as argument to the Subject?
  • Should I take a different approach?

Hope I'm clear enough. Thanks everyone in advance.

1

1 Answers

0
votes

Try to memorize being clicked inside the child-item-component by using the click-directive.

Something like this:

TS-file

// I guess this is something similar to your Subject-Solution
@Input() dragEnabled: Subject<boolean> = new Subject();

// your memory of being clicked
private isClicked: boolean = false;

...

constructor(){
    this.dragEnabled.subscribe( () => {
       this.onDragEnabledEvent();
    });
}

private clicked(): void {
   this.isClicked = true;
}

...

// this method is triggered by your Subject out of the subscription
// only the clicked element is blocked all the others get unblocked
onDragEnabledEvent(): void {
    if(this.isClicked) {
        this.isClicked = false; // reset

        // YOUR BLOCKING CODE GOES HERE

    } else

        // YOUR UNBLOCKING CODE GOES HERE

    }
}

HTML-Template

<child-item-component *ngFor="let date of shift?.dates" [shift]="shift"
[dragEnabled]="dragEnabled" (click)="clicked()"></child-item-component>

dragEnabled

Be aware of the fact that a Subjects only fires a new event if the content changes. As the content itself is not of interest for you I'd suggest the following:

Send the current Date as an UTC timestamp string

subject.next(new Date().getTime());

This will always come up with a new value and your subscription always fires.