25

I have done a lot of work with the new Angular2 Framework recently. While testing out some of the features, I ended up with the error:

Can't bind to 'ngStyle' since it isn't a known native property

While investigating the error itself I came to several solutions, like adding the 'directive: [NgStyle]' to the component, but this does not solve the problem.

The code is like following:

main.ts

import {bootstrap} from 'angular2/platform/browser';
import {App} from './app'

bootstrap(App).then(error => console.log(error));

app.ts

import { Component } from 'angular2/core';
import { Button } from './button';
import { NgStyle } from "angular2/common";

@Component({
    selector: 'app',
    template: '<h1>My First Angular 2 App</h1><button>Hello World</button>',
    directives: [Button, NgStyle]
})
export class App { }

button.ts

import {Component} from "angular2/core";
import {NgStyle} from "angular2/common";

@Component({
    selector: 'button',
    host: {
        '[ngStyle]': 'style()'
    },
    templateUrl: '<ng-content></ng-content>',
    directives: [NgStyle]
})
export class Button {
    style() {
        return {
            'background': 'red'
        }
    }
}

Thank you for your help.

HDJEMAI
  • 9,436
  • 46
  • 67
  • 93

4 Answers4

64

That happens when you do not import the CommonModule module. In the recent version of Angular, all DOM level directives are grouped under the same module.

import { CommonModule } from '@angular/common';

You can import NgClass or NgStyle individually but Angular soon throws an error if you end up using the same in multiple components accessed via router.

HDJEMAI
  • 9,436
  • 46
  • 67
  • 93
codef0rmer
  • 10,284
  • 9
  • 53
  • 76
5

If you need full flexibility, over what host provides

host: {
  '[class.someName]':'someValue',
  '[style.someProp]':'someValue'
}

you need to use imperative ways like

@Component({ ... }) 
export class SomeComponent {
  constructor(private renderer:Renderer, private elementRef:ElementRef) {}
  someMethod() {
    this.renderer.setElementClass(
        this.elementRef.nativeElement, this.getClassFromSomewhere());
    this.renderer.setElementStyle(
        this.element.nativeElement, 'background-color', this.getColor());
  }
}

or other methods Renderer provides.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
2

Please note, i have found a solution, while writing this question. And i like to share it, so that other people do not have to search an eternity.

Please take a look at the following link:

Angular2 Exception: ngClass within a Host, "isn't a known native property"

As 'Günter Zöchbauer' describes, it is not possible to use directives in host bindings. And he comes with a solution for ngClass.

And here is a simple solution for my problem:

button.ts

import {Component} from "angular2/core";
import {NgStyle} from "angular2/common";

@Component({
    selector: 'button',
    host: {
        '[style]': 'styleAsString()'
    },
    templateUrl: 'app/button.html',
    directives: [NgStyle]
})
export class Button {
    styleAsString() {
        let style = {
            background: 'red'
        };

        return JSON.stringify(style).replace('{', '').replace('}', '').replace(/"/g, '');
    }
}

Note, that this is not a perfect solution because it lacks while 'compiling' the object to plain css. I simply replace all occurences of ' " ' which results in an odd behaviour when using 'url(" "), ...'. Hope that i could help somebody with the same or a similar question.

Community
  • 1
  • 1
  • I like your approach. I reached my vote limit today - will +1 later. Actually I would try to avoid it but I find it interesting that it's working this way. – Günter Zöchbauer Apr 08 '16 at 15:48
  • Yes, it is a little bit of a hack i think, but it does work. This may be also a good solution if the stylesheet is delivered as plain text loaded from a server or a file. This depends on the Renderer class and its possibilities to add stylesheet that already is plain text. – Marcel Jöstingmeier Apr 08 '16 at 15:54
  • 4
    Answer is out of date since `directives` is no longer used – Jackie Nov 10 '16 at 21:14
2

If someone gets this error on unit testing with karma.

I was getting this error with Karma testing. I solve this by importing FlexLayoutModule

example

import { MaterialModule } from '@app-modules/material.module.ts';
import { FlexLayoutModule } from '@angular/flex-layout';
import { DashboardComponent } from './dashboard.component';

describe('DashboardComponent', () => {
  let component: DashboardComponent;
  let fixture: ComponentFixture<DashboardComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [ MaterialModule, FlexLayoutModule ],
      declarations: [
        DashboardComponent
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(DashboardComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

I hope someone helped with this answer.

Dmitriy
  • 5,525
  • 12
  • 25
  • 38
George C.
  • 331
  • 2
  • 6