8
votes

I'm using Angular 2.0 final release.

What i want to do? - i want to show some notifications (warnings, the requirements for the input) only when the input receive focus. Or even better, when his parent (the div) has mouse hover event.

Doing this from the parent(the div) is easy. Just (focus)=showNotifications() + an ngIf - and the job is done.

But i want to encapsulate this functionality inside the show-notifications component - and make it reusable..

Given that i pass the control inside the show-notifications using @Input() - i could do both this things if i have access to the native HTML input element.You can see how in show-notifications.component.ts. Here is the code:

app.component.html:

`<div>
   <label>Name: </label>
   <input formControlName="myName">
   <show-notifications [the_control]="myName" ></show-notifications>
</div>`

app.component.ts:

export class AppComponent {
    myName = new FormControl("defaultvalue",[some validators..])
}

show-notifications.component.html:

<div class="show_requirements" *ngIf="hasfocus or parentDivHasMouseHover"> // incorect code and logic - i know, but you can see the idea..

    <p *ngFor="let requirement of thisInputRequirements">{{requirement}}<p>

</div>

show-notifications.component.ts:

export class ShowNotificationsComponent {

    @Input() the_control;
    this.thisInputRequirements = // take them form firebase.
    this.thisInputCustomErrorMessages = // take them from firebase.

    // I implemented all this and works amazing but i want to do:

    //something like this:

    ngOnInit(){
        this.nativeInputElement = this.the_control.getNativeElement() // this of course doesn't work

        // the requirements are shown only when the input receive focus
        let source = Rx.DOM.focus(this.nativeInputElement);
        source.subscribe( x => this.hasFocus = true)

        // Or even better: 
        // the requirements are shown only when the parent has mouse hover
        // or any other event / endles posibilites here..

        let parent = getParentOf(this.nativeInputElement)
        let source = Rx.DOM.mouseover(parent);
        source.subscribe( x => this.parentDivHasMouseHover = true) // this will be some toggling functionality.
    }

}

Question:

How do i access the native element given that i have the formControl (myName = the_control) object?

Is there a better way to do notifications in a separate component - and make it reusable? I already use this successfully throughout my entire app - to show errors and input requirements..

Note: I tried to pass the hole html input first using hashtag syntax ( #myInput ) and form there, inside the show-notifications component, i tried to do: myInput.myName - to acces the control but i get undefined. The controls are not present on the native input element. And I need that control for validation:)

3
One option would be to create a custom form control. You could let the user pass in the HTML with a #input so you can bind it to the ControlValueAccessor field to be used. - Juan Mendes

3 Answers

4
votes

I think you could use # notation to pass the element to ShowNotificationsComponent:

export class ShowNotificationsComponent {
    @Input() the_control;
    @Input() elm;
    //...
}

Then in the template:

<input formControlName="myName" #elm>
<show-notifications [the_control]="myName" [elm]="elm"></show-notifications>
0
votes

I found something that may be helpfull if you want to get some information from the Abstractcontrol as it was a normal Html Input Element, for example if you want to add a "Event Listener" to it, in order to know when user is interacting with the element, It could be done by using the valueChanges or statusChanges, both Observables from class AbstractControl, i used it to know when a element has changed and get the option selected to do more actions before the form is submited, I leave here my code example:

getValue() {
  this.myForm.get('myControlName').valueChanges.subscribe((optionValue) => {
    console.log(optionValue);
    this.doSomething(optionValue);
  });
}

And if you want to made some animation or changes when the user hover the parent maybe you can use some simple css trick like this:

.parent #child{
  opacity: 0;
}

.parent:hover #child{
  opacity: 1;
}

You can check this documentation for more details : https://angular.io/api/forms/AbstractControl#valueChanges

-3
votes

This is very Basic. FormContrl is not required. you should create a local variable on input element with # and pass local variables to method

<div>
<label for="firstname">First Name</label>
<input name="fname" #nameFirst />
<label for="lastname">Last Name</label>
<input name="lname" #nameLast />
</div>
<button (click)="send(nameFirst , nameLast)">Submit</button>

export class HtmlExample {

    send(firstName: HTMLInputElement, lastName: HTMLInputElement): void {
        console.log(`Hello ${firstName.value}  ${lastName.value}`);
        firstName.value = '';
        lastName.value = '';
    }

}