20

Maybe this is normal behavior, making a test, this.myColor It is undefined, but why? That mistake wrong in my code:

<h1 myDR [myColor]="red" > Test </h1>

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

@Directive({
    selector: '[myDR]',
    host:{
        '(mouseenter)' : ' mouseEnter()'
    }
})

export class MyDi {
    
    @Input () myColor: string;
    
    constructor(private el:ElementRef) {
        
    }
    
    mouseEnter(){
      
        this.el.nativeElement.style.backgroundColor = this.myColor;
    
        console.log(this.myColor);
     }
}

@Component({
    selector: 'my-app',
    template: `<h1>Hello World Angular2</h1> 
 
              <h1 myDR [myColor]="red" > Test </h1>
              `,
    directives: [MyDi]
})

export class App {
    constructor(){
        
    }
}

You can move the mouse over "Test" and look in the Console

Plunker

Community
  • 1
  • 1
Angel Angel
  • 19,670
  • 29
  • 79
  • 105

2 Answers2

51

You have to enclose your input binding in simple quotes, like this

[myColor]="'red'"

This will bind the red string to myColor. If you remove the simple quotes it will look for a class property named red which doesn't exist therefore it returns undefined

You can do it as I mentioned above, or you can create a class property named red. In this case it will bind to the class property.

@Component({
    template: `<h1 myDR [myColor]="red" > Test </h1>`
})

export class App {
    red: string = 'red';
}

Edit

I forgot to mention that accessing the DOM through nativeElement is discouraged. You should use Renderer, @HostBinding or the host property in @Component (the last two are equivalent). So you have three more options

  • Using host property
@Directive({
    host:{
        '(mouseenter)' : ' mouseEnter()',
        '[style.background-color]' : 'myColor'
    }
})

mouseEnter(){
    this.myColor = 'blue';
}
  • Using @HostBinding (this case will set the color immediatly)
@HostBinding('style.background-color') get color {
    return this.myColor;
}

mouseEnter(){
    this.myColor = 'blue';
}
  • Using Renderer (use this instead of nativeElement.style = 'value')
constructor(public renderer: Renderer, public element: ElementRef) {}

mouseEnter(){
  this.renderer.setElementStyle(this.element.nativeElement, 'background-color', this.myColor);
}
Eric Martinez
  • 31,277
  • 9
  • 92
  • 91
  • Ohh, it's true, I feel stupid now. thanks for your time. – Angel Angel Mar 15 '16 at 00:06
  • 1
    @AngelAngel you're welcome. I updated my answer with something it may interest you. – Eric Martinez Mar 15 '16 at 00:14
  • its update is really useful, it is possible to adapt the title of my question to make it easier to access your answer with the information of the update, I think I could help others learn these ways – Angel Angel Mar 15 '16 at 00:19
  • something like: @Input undefined Angular 2 using native Element, for example? – Angel Angel Mar 15 '16 at 00:21
  • @AngelAngel I think it's fine like it is, I wouldn't worry about it. But it's your call, it's your question :P – Eric Martinez Mar 15 '16 at 00:21
  • 1
    Eric and @AngelAngel, Eric's update would be good to put into another question, "What are some good alternatives to accessing the DOM using nativeElement?" – Mark Rajcok Mar 19 '16 at 22:41
  • Eric I just created a question that says @MarkRajcok http://stackoverflow.com/questions/36108995/what-are-some-good-alternatives-to-accessing-the-dom-using-nativeelement-in-angu – Angel Angel Mar 20 '16 at 00:40
  • Can I ask where this comes from: "accessing the DOM through nativeElement is discouraged"? angular.io is using nativeElement in their attribute directives example: https://angular.io/docs/ts/latest/guide/attribute-directives.html. Thanks. – Paul Evans Dec 05 '16 at 15:14
8

A simpler way for binding static text is

<h1 myDR myColor="red" > Test </h1>

See Angular2 documentation under "One-time string initialization".

Plunker

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • it is true, I had not thought, in that alternative thanks for your reply is good to keep in mind – Angel Angel Mar 20 '16 at 00:35
  • 4
    Günter, this comment is for other readers (since we've had a good discussion about this in other comments): I don't really like this shorthand notation because it looks like just an HTML attribute. We have to examine the component definition to determine if `myColor` is an input property. If it is, then this syntax also populates the input property with the value `red`. If it isn't, then it is just an HTML attribute. I find that ambiguous. I much prefer to see the `[]`s whenever we want to affect a directive or a component property. They immediately tell us that we're property binding. – Mark Rajcok Mar 20 '16 at 02:23
  • @MarkRajcok Thanks for that explanation, I didn't understand the difference of using with [] and without [], and your explanation cleared it up. It is better to use with [] and set the value with a single quote inside a double quote string like `[prop]=" 'literalValue' "` because it is obvious that we are property binding, not just setting an HTML attribute. Also, this way it doesn't set that `prop` as an HTML attribute but rather it only creates a ng-reflect attribute. – TetraDev Oct 06 '16 at 17:47