24

I'm trying to create my own directive in Angular 4. But, I got this error when bind the property of class into component template.

Console error:

Unhandled Promise rejection: Template parse errors: Can't bind to
'data' since it isn't a known property of 'tree'. ("<tree [ERROR
->][data]="data"></tree>"):

My tree-view-component.ts:

@Component({
    selector: 'app-tree-view',
    template: '<tree [data]="data"></tree>'
})
export class TreeViewComponent implements OnInit {

    @Input() data: any[];

    constructor() {
        this.data = [
        {
            label: 'a1',
            subs: [
                {
                    label: 'a11',
                    subs: [
                        {
                            label: 'a111',
                            subs: [
                                {
                                    label: 'a1111'
                                },
                                {
                                    label: 'a1112'
                                }
                            ]
                        },
                        {
                            label: 'a112'
                        }
                    ]
                },
                {
                    label: 'a12',
                }
            ]
         }
     ];
  }

  ngOnInit() { }

}

Here is my complete script file: https://pastebin.com/hDyX2Kjj

Is there anyone know about this? TiA

Brian Burns
  • 20,575
  • 8
  • 83
  • 77
Justinus Hermawan
  • 1,194
  • 1
  • 23
  • 44
  • 2
    You don't need to mark inputs twice, either ` inputs: ['data'],` or `@Input()` if you have both, one is redundant. Did you add `Node` to `declarations of `@NgModule()`? – Günter Zöchbauer Mar 31 '17 at 05:41
  • https://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5 provides a ready to use Angular2 template - just press the "new" button and "Angular". – Günter Zöchbauer Mar 31 '17 at 05:42
  • It was solved with added TreeNodeComponent, TreeComponent, adn TreeViewComponent to declarations array in @NgModule(). Is there another way to include TreeViewComponent only in @NgModule() without TreeNodeComponent and TreeComponent? Because I already included its in TreeViewComponent. – Justinus Hermawan Mar 31 '17 at 05:49
  • Sorry, I don't know what you mean with "Because I already included its in TreeViewComponent." Do you mean `TreeViewModule`? – Günter Zöchbauer Mar 31 '17 at 05:51
  • I did `import { TreeNodeComponent } from './tree-view.node.component';` in TreeComponent and `import { TreeComponent } from './tree.component';` in TreeViewComponent. Why should I include them again in app.module? Doesn't it enough with just including TreeViewComponent in declarations? – Justinus Hermawan Mar 31 '17 at 05:57
  • TypeScript imports and declarations are two entirely different and unrelated concepts. Every component, directive, pipe, needs to be registered in `@NgModule({ declaration: []})`. Either in `AppModule` or a module added to `imports: []` of `AppModule` (direct or transitive). – Günter Zöchbauer Mar 31 '17 at 06:00
  • Can it be the same if I create a TreeModule, which means it will be separated with AppModule, and add TreeNodeComponent, TreeComponent, and TreeViewComponent into TreeModule declarations, and then import TreeModule to AppModule, So, I don't need add them into AppModule declarations again? – Justinus Hermawan Mar 31 '17 at 06:04
  • Exactly. This is called a feature module and will work fine. This makes it easier to reuse the tree in other modules. You need to import the module that contains directives you use into every module where you use them and directives (and components and pipes) can only be in `declarations: []` of exactly one module. – Günter Zöchbauer Mar 31 '17 at 06:06
  • Oh, I see now. Thank you for your great explanation :) – Justinus Hermawan Mar 31 '17 at 06:09

4 Answers4

27

Every component, directive, and pipe needs to be registered in @NgModule()

@NgModule({
  declarations: [TreeViewComponent]
})
export class AppModule {}

For more details see

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

I've the same error, when run test for ParentComponent. Inside was ChildComponent component with @Input property: string;. Both components were also declared inside app.module.ts.

I've fixed this like that (parent component test file):

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ParentComponent, ChildComponent]// added child component declaration here
    })
      .compileComponents();
  }));


Kamil Naja
  • 6,267
  • 6
  • 33
  • 47
2

As The Aelfinn pointed out if you are using your Component across Modules you need to export it. BUT you should not import, export and declare it in the Module you want to use it, since its not part of this Module !!!
So suppose you have a TreeViewStuffModule which declares the TreeViewComponent and a DoSomethingWithTreeViewModule where the TreeViewComponent is used in, your declarations would be as follows:

@NgModule({
  declarations: [
    TreeViewComponent
  ],
  exports: [
    TreeViewComponent
  ]
})
export class TreeViewStuffModule { }

@NgModule({
  imports: [
    TreeViewStuffModule
  ]
})
export class DoSomethingWithTreeViewModule
D4rth B4n3
  • 1,268
  • 2
  • 17
  • 26
-1

If you are using TreeViewComponent in another module, you will need to import the component into the @NgModule as follows:

@NgModule({
    imports: [TreeViewComponent],
    // This says that all components in this module can import TreeViewComponent
    exports: [ThisModulesComponents],
    declarations: [ThisModulesComponents]
})
export class ModuleDependentOnTreeViewComponent
The Aelfinn
  • 13,649
  • 2
  • 54
  • 45