1
votes

I try to create custom component which looks like search form. I have created SearchComponent with selector my-search inside of which I have placed HTML <input> element with attached directive InputDirective with selector [myInput]:

<my-search>
  <input myInput>
</my-search>

The issue is how to detect changes from InputDirective inside of SearchComponent? For example: I should enable or disable button when user types some text into input:

search.component.html

<ng-content select="[myInput]"></ng-content>
<button type="button" [disabled]="!searchText">Search</button>

I try to subscribe on changes of directive inside of component, but it does not work.

search.component.ts

@Component({
  selector: 'my-search',
  templateUrl: './search.component.html'
})
export class SearchComponent implements AfterContentInit {
  @ContentChild(InputDirective) input: InputDirective;

  ngAfterContentInit() {
    this.input.changes.subscribe(changes => console.log(changes));
  }
}

Also I try to export native input in property element.

input.directive.ts

@Directive({
  selector: '[myInput]'
})
export class InputDirective {
  element: HTMLInputElement;

  constructor(private elementRef: ElementRef) {
    this.element = this.elementRef.nativeElement;
  }
}

And when try to get value of input with getter, but it does not work too.

search.component.ts

@Component({
  selector: 'my-search',
  templateUrl: './search.component.html'
})
export class SearchComponent implements AfterContentInit {
  @ContentChild(InputDirective) input: InputDirective;

  get searchText(): string {
    return this.input.element.value;
  }
}

Can anyone help me with this? Here is link for experiments.

3
Would a simple setter work for you?DeborahK
I added this setter, but it changes nothing. set searchText(value: string) { this.input.element.value = value; }Yuri Beliakov

3 Answers

1
votes

looks like you're not actually getting down to the input element you're trying to monitor, try:

@Component({
  selector: 'my-search',
  templateUrl: './search.component.html'
})
export class SearchComponent implements AfterContentInit {
  @ContentChild(InputDirective) input: InputDirective;

  ngAfterContentInit() {
    this.input.element.addEventListener('change', e => console.log(this.input.element.value));
  }
}

is that what you're looking for?

0
votes

In Angular(version 2+) we have something call EventEmitter using which child component can emit any of its changes

    Below is what you need in your child component
     1)@Output() change: EventEmitter<string> = new EventEmitter<string>();

    2)Also add a method that emits change when keypress event occurs
        onKeyPress(value: string) {
                this.change.emit(value);
            }
    3)change your html
    <my-search>
      <input myInput (change)="searchChange($event)">
    </my-search>

     4)change your boolean "searchText" in the method searchChange as below
       public searchChange(event:any)
{
if(event && event.length>0)
searchText=true
}
-1
votes

What you are looking for is a HostListener in your directive :

  @HostListener('keypress') changed;

You can look more into it and which events are available but change will trigger everytime you press on search button, you got others like 'keydown' but you should try it out

Here is a list of more events if you wanna have a look https://www.w3schools.com/tags/ref_eventattributes.asp

Edit: you can even make some more by adding to the Change a method body to trigger an output event back to the parent component to keep processing that event, but for what I understood from your question that hostlistener will do.