Angular2 on focus event to add class

21,356

Solution 1

Update

@Directive({selector: '.md-input', host: {
  '(focus)': 'setInputFocus(true)',
  '(blur)': 'setInputFocus(false)',
}})
class MaterialDesignDirective {
  MaterialDesignDirective(private _elementRef: ElementRef, private _renderer: Renderer) {}
  setInputFocus(isSet: boolean): void {
    this.renderer.setElementClass(this.elementRef.nativeElement.parentElement, 'md-input-focus', isSet);
  }
}

Original

This can easily be done without ElementRef and Renderer (what you should strive for in Angular2) by defining host bindings:

import {Directive, ElementRef, Renderer, Input} from 'angular2/core';

@Directive({
      selector: '.mdInput',
      host: {
        '(focus)':'_onFocus()',
        '(blur)':'_onBlur()',
        '[class.md-input-focus]':'inputFocusClass'
      }

})

export class MaterialDesignDirective {
      inputFocusClass: bool = false;

      _onFocus() {
        this.inputFocusClass = true;
      }

      _onBlur() {
        this.inputFocusClass = false;
      }
}

or a bit more terse

@Directive({
      selector: '.mdInput',
      host: {
        '(focus)':'_setInputFocus(true)',
        '(blur)':'_setInputFocus(false)',
        '[class.md-input-focus]':'inputFocusClass'
      }

})

export class MaterialDesignDirective {
      inputFocusClass: bool = false;

      _setInputFocus(isFocus:bool) {
        this.inputFocusClass = isFocus;
      }
}

I tried it only in Dart where it works fine. I hope I translated it correctly to TS.

Don't forget to add the class to the directives: of the element where you use the directive.

Solution 2

In addition to previous answers, if you don't want to add a directive, for the specific component (you already have a directive for a parent component, you are using Ionic 2 page or something else), you inject the renderer by adding private _renderer: Renderer in the page constructor and update the element using the event target like this:

html:

(dragstart)="dragStart($event)"

TS:

dragStart(ev){
    this._renderer.setElementClass(ev.target, "myClass", true)
}

Edit: to remove the class just do:

dragEnd(ev){
    this._renderer.setElementClass(ev.target, "myClass", false)
}
Share:
21,356
Mad Eddie
Author by

Mad Eddie

Updated on June 19, 2020

Comments

  • Mad Eddie
    Mad Eddie about 4 years

    I'm looking to update an Angular 1 app to Angular 2 and am having an issue with one of my old directives.

    The idea is simple. When an input field is focused a class should be added (md-input-focus) and another be removed (md-input-wrapper). Then this process should be reversed on "blur" event - i.e. focus lost.

    My old directive simply included the lines

    .directive('mdInput',[
        '$timeout',
        function ($timeout) {
            return {
                restrict: 'A',
                scope: {
                    ngModel: '='
                },
                link: function (scope, elem, attrs) {
                    var $elem = $(elem);
                    $elem.on('focus', function() {
                          $elem.closest('.md-input-wrapper').addClass('md-input-focus')
                    })
                    .on('blur', function() {
                     $(this).closest('.md-input-wrapper').removeClass('md-input-focus');
                    })
                 }
    

    etc...

    I obviously have the classic start to my directive but have run out of.....skill

    import {Directive, ElementRef, Renderer, Input} from 'angular2/core';
    
    @Directive({
          selector: '.mdInput',
    
    })
    
    export class MaterialDesignDirective {
          constructor(el: ElementRef, renderer: Renderer) {
               // Insert inciteful code here to do the above
          }
    }
    

    Any help would be appreciated.

    UPDATE:

    The HTML would look like (before the input element was focused):

    <div class="md-input-wrapper">
       <input type="text" class="md-input">
    </div>
    

    and then

    <div class="md-input-wrapper md-input-focus">
       <input type="text" class="md-input">
    </div>
    

    after.

    The input element is the only one which can receive a focus event (and therefore the target for the directive) however the parent <div> requires the class addition and removal.

    Further help

    Please see Plunker for help/explanation - would be great if someone could help