简体   繁体   中英

Angular2 trigger directive from component on click

I have a directive that adds box shadow to any hovered element on page but I need it to start applying the shadow after a click of a button. The problem I have, is it only applies to a single element.

Here is an image of the box shadow

It applies only to the header after I hover it. I need it to apply to any hovered element.

My app.component:

@Component({
  moduleId: module.id,
  selector: 'my-app',
  template: `
    <h1 myHighlight="orange">{{title}} {{clickedElement | async}}</h1>
    <nav>
      <a routerLink="/dashboard" routerLinkActive="active">Dashboard</a>
      <a routerLink="/heroes" routerLinkActive="active">Heroes</a>
      <a routerLink="/secret-heroes" *ngIf="authService.loggedIn()" routerLinkActive="active">Secret Heroes</a>
      <a (click)=authService.login() *ngIf="!authService.loggedIn()">Log In</a>
      <a (click)=authService.logout() *ngIf="authService.loggedIn()">Log Out</a>
      <a (click)=giveFeedback()>Give Feedback</a>
      <a (click)="listening = !listening" >Give Feedback2</a>

      <button id="modalButton" type="button" (click)="feedbackModal.show()">test</button>
      <my-feedback-modal>
      </my-feedback-modal>

    </nav>
    <router-outlet></router-outlet>
  `,
  styleUrls: ['app.component.css']
})
export class AppComponent {
  //@Input() highlight: boolean = false;
  title = 'Tour of Heroes';

  @ViewChild(ModalComponent) modal: ModalComponent;
  @ViewChild(HighlightDirective) highlightDir: HighlightDirective;

  @ViewChild(FeedbackModalComponent) feedbackModal: FeedbackModalComponent;

  constructor(private authService: AuthService, private el: ElementRef, private cdr: ChangeDetectorRef) {
    this.cdr = cdr;
  }

  clickedElement:BehaviorSubject<ElementRef> = new BehaviorSubject(this.el);

  ngAfterViewInit() {
    //this.clickedElement.next(this.highlightDir.getElement().nativeElement.nodeName);
  }

  ngDoCheck() {

  }

  giveFeedback(): void {

        this.highlightDir.startFeedback();
        this.cdr.detectChanges();
        //this.highlight = true;
  }
}

My highlight.directive:

@Directive({
  selector: 'a, abbr, address, article, body, br, button, div, h1, h2, h3, h4, h5, h6, header, hr, i, iframe, img, ' +
  'input, label, li, link, meta, nav, object, ol, option, output, p, param, pre, section, select, small, source, span,' +
  'summary, table, tbody, td, textarea, tfoot, th, thead, time, title, tr, u, ul, video'
})
export class HighlightDirective {
    elementsArray: string[];
    listening: boolean = false;

    constructor(private el: ElementRef, private cdr: ChangeDetectorRef) {
        this.cdr = cdr;
        this.elementsArray = ["a", 'abbr', 'address', 'article', 'body', 'br', 'button', 'div', 'h1', 'h2', 'h3', 'h4', 'h5'
        , 'h6', 'header', 'hr', 'i', 'iframe', 'img', 'input', 'label', 'li', 'link', 'meta', 'nav', 'object', 'ol', 'option'
        , 'output', 'p', 'param', 'pre', 'section', 'select', 'small', 'source', 'span', 'summary', 'table', 'tbody', 'td'
        , 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'u', 'ul', 'video'];
    }

    //@Input() defaultColor: string;
    //@Input() listening: boolean = false;
    //check: boolean = false;

    public getElement(): ElementRef {
        return this.el;
    }

    public startFeedback(): boolean {
        this.listening = true;
        this.cdr.detectChanges();

        return true;
    }

    @HostListener('click') onClick() {
        if(this.listening) {

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

            this.listening = false;
        }
    }

    @HostListener('mouseenter') onMouseEnter() {
        if(this.listening) {

            this.el.nativeElement.style.boxShadow = '0 0 0 5px yellow';
            this.el.nativeElement.parentNode.style.boxShadow = null;
        }
    }

    @HostListener('mouseleave') onMouseLeave() {
        if(this.listening) {

            this.el.nativeElement.style.boxShadow = null;
            this.el.nativeElement.parentNode.style.boxShadow = '0 0 0 5px yellow';

            let check = false;

            for (let entry of this.elementsArray) {
                if (this.el.nativeElement.parentNode.nodeName == entry.toUpperCase()) {
                    check = true;
                    break;
                }
            }

          if (!check)
            this.el.nativeElement.parentNode.style.boxShadow = null;
        }
    }
}

Any help would be greatly appreciated.

The problem is that you use @ViewChild instead of @ViewChildren . With ViewChild it only addresses the first instance of HighlightDirective it can find in the template.

Besides some other obscure choices you made here, I would say you have to change to something like this:

@ViewChildren(HighlightDirective) highlightDirs: QueryList<HighlightDirective>;

You then have to change your giveFeedback function to this:

giveFeedback(): void {
    this.highlightDirs.forEach((highlightDir: HightlightDirective) => {
       highlightDir.startFeedback();
    });
}

There is no need for the changeDetectionRef inside any of your code. This is only necessary if you put changeDetection: ChangeDetectionStrategy.OnPush on your component/directive

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM