3

Objective

  • I have a form with some input elements (el1, el2 ...)
  • el1 might have focus on beginning or not
  • when keydown event fires, do the following:
    • if none of the input elements have focus, set focus to the first non empty element
    • if any of the input elements have focus, check if enter was pressed, if it was move to a next arbitrary element
    • in any other case, just let the key do what its intention was

My current code

form.component.html

<form>
      <input type="text" class="form-control" id="el1" name="el1"
             required focus
             [(ngModel)]="el1" #el1
             (keydown)="processEl1KeyDown($event)"
      >
      <input type="text" class="form-control" id="el2" name="el2"
             required
             [(ngModel)]="el2" #el2
             (keydown)="processEl2KeyDown($event)"
      >
</form>

form.component.ts

@Component({
    selector: 'my-form',
    templateUrl: 'app/form.component.html'
})
export class FormComponent {

    constructor(private renderer:Renderer) {
    }

    el1: string;
    el2: string

    @ViewChild("el1")
    el1El: ElementRef;

    @ViewChild("el2")
    el2El: ElementRef;


    @HostListener('document:keydown', ['$event'])
    handleKeyboardEvent(event: KeyboardEvent) {
        if (!this.el1) {
            this.setFocus(this.el1El);
        } else {
            this.setFocus(this.el2El);
        }
    }


    processEl1KeyDown(event: KeyboardEvent) {
        event.stopPropagation();
        if (event.keyCode == 13) {
            this.setFocus(this.el2El);
        }
    }


    processEl2KeyDown(event: KeyboardEvent) {
        event.stopPropagation();
        if (event.keyCode == 13) {
            this.submitForm();
        }
    }

    submitForm() {
        console.log("submit form");
    }

    setFocus(element: ElementRef) {
        this.renderer.invokeElementMethod(element.nativeElement, 'focus');
    }
}

Questions

  1. How can I get template variable name of a focused element (eg #el1, #el2) from within FormComponent class? document.activeElement returns DOM element.
  2. Can I get Angular2 object from a DOM? something like ElementRef.create('<div></div>')
  3. If I want to pass arbitrary string to my setFocus('el1') function, how can I build ElementRef from that? I can use @ViewChild decorator, but I need something which can be defined during runtime? like new ViewChild('el1')
  4. What would be more "Angular2" way of solving my problem? With a BehaviorSubject as mentioned in this answer - Delegation: EventEmitter or Observable in Angular2?

Edit

Maybe questions are not clear enough. To sum up: If I have n input elements (el1, el2 ... eln), how do I know in module which element has focus (maybe via template variable) and then move focus to a different element (via a string, which corresponds to another template variable again). I think I am looking at angular.element equivalent - Get ComponentRef from DOM element, but I believe this might not be the right way.

Community
  • 1
  • 1
zeldi
  • 4,833
  • 3
  • 19
  • 18
  • http://stackoverflow.com/questions/34522306/angular-2-focus-on-newly-added-input-element – Günter Zöchbauer Aug 19 '16 at 04:40
  • @Günter: I am aware of this question, however, I do not know how does it relate to my question. Maybe I am doing something conceptually wrong. I did rephrase my question, maybe now it is more clear. – zeldi Aug 23 '16 at 21:06
  • Didn't look too close at your question. Just thought linking to it might be helpful. – Günter Zöchbauer Aug 24 '16 at 04:00

1 Answers1

1

I think a focus directive might solve most of the problems you listed. I had similar issues and have written this directive to solve them:

@Directive
({
    selector: '[hasFocus]'
})

export class HasFocusDirective
{
    @Input("hasFocus") hasFocus: boolean;
    constructor(private elementRef: ElementRef) {}

    ngAfterViewInit()
    {
        if (this.hasFocus)
        {
            this.elementRef.nativeElement.focus();
        }
    }

    ngOnChanges(changes: SimpleChanges)
    {
        if (changes["hasFocus"] && changes["hasFocus"].currentValue === true)
        {
            this.elementRef.nativeElement.focus();
        }
    }
}

[hasFocus] is a boolean and you can use any boolean expression to dynamically control focus of elements that use it.

hholtij
  • 2,906
  • 6
  • 27
  • 42
  • @Directive and SimpleChanges might be the right direction, but how do I determine from a component which element is focused? Can you give me an example for this? – zeldi Aug 19 '16 at 11:00