Matt Brewerton
Matt Brewerton

Reputation: 896

Angular Access data from Component in Directive

So I'm trying to build an "autocomplete" directive for a project that will query the API and display a list of results to select from. I have a component that displays a modal with a simple input box. I need to be able to type into the box to search Members, click on a member and add that to an array in the component.

Edit: The issue I'm having is that when I call this.wlAutocomplete.next(value);, it goes back into my component and makes the API call with the correct value from the input field, it doesn't return the data back to the directive to handle the response from the API there.

StackBlitz Example: https://stackblitz.com/edit/angular-11erew

The Component will track the array of selected members. I need to be able to:

My component has a method:

queryMembers(value: string): Subscription {
  return this.memberService.query({ term: value, groupKey: this.group.groupKey })
    .subscribe((members) => {
      console.log(members);
      return this.searchMemberList = members;
    });
}

Which I'm using in the template like this:

<input (wlAutocomplete)="queryMembers($event)" class="uk-search-input" type="search" placeholder="Search...">

Here is the code for the Directive:

@Directive({
  selector: 'input[wlAutocomplete]'
})
export class AutocompleteDirective {
  modelChanged: Subject<string> = new Subject<string>();
  subscription: Subscription;
  debounce: number = 500;

  constructor() {
    this.subscription =
      this.modelChanged
        .pipe(debounceTime(this.debounce))
        .subscribe(value => {
          this.wlAutocomplete.next(value); // I need to get the data from component method passed into `wlAutocomplete`
        });
  }

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

  @HostListener('input', ['$event'])
  onChange($event) {
    this.modelChanged.next($event.target.value);
  }
}

Upvotes: 0

Views: 327

Answers (1)

FussinHussin
FussinHussin

Reputation: 1814

Alright I think I understand what you are trying to do now, thanks for the example. You want to send values from the parent template to the directive? basically you need inputs for your directive, and bind to them in the parent.

check out this question for more

import {Directive, EventEmitter, HostListener, Input, Output} from '@angular/core';
import {Subject, Subscription} from "rxjs";
import {debounceTime} from "rxjs/operators";

@Directive({
  selector: 'input[wlAutocomplete]'
})
export class AutocompleteDirective {
  modelChanged: Subject<string> = new Subject<string>();
  subscription: Subscription;
  debounce: number = 500;

  // label and type your input, then handle it however you like
  @Input() value: any;

  constructor() {
    this.subscription =
      this.modelChanged
        .pipe(debounceTime(this.debounce))
        .subscribe(value => {
          console.log('value', value)
          console.log('directive', this.wlAutocomplete.next(value)); // I need to get the data from component method passed into `wlAutocomplete`
        });
  }

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

  @HostListener('input', ['$event'])
  onChange($event) {
    console.log('directive called')
    this.modelChanged.next($event.target.value);
  }
}

template

// bind to the input in the template
    AutoComplete: <input type="text" [value]="value" (wlAutocomplete)="queryMembers($event)" />

component

import { Component } from '@angular/core';
import {Subscription} from "rxjs";
import {MemberService} from './member.service'
import {Member} from './member';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  // send value to directive 
  value: any;
  name = 'Angular';
  group: any = { groupKey: 'test' };
  debugMemberList: Member[];
  constructor(private memberService: MemberService){}

  queryMembers(value: string): Subscription {
  return this.memberService.query({ term: value, groupKey: this.group.groupKey })
    .subscribe((members) => {
      console.log('In component: ', members);
      this.value = members;
      return this.debugMemberList = members;
    });
  }
}

I'm not sure if this is the exact implementation you are looking for but hopefully that give you enough info on transferring data between the parent and directive to figure it out.

Upvotes: 1

Related Questions