Sakala
Sakala

Reputation: 91

No provider for String

Hi can somebody tell Me what am I doing wrong? I think it's simple error, but I'm new to angular and I can't find it.

EXCEPTION: No provider for String! (SwNavItemCmp -> String)

export interface SwNavItemModel {
	name: string;
  route: string;
  children?: Array<SwNavItemModel>;
}

import {SwNavItemModel} from '../models/sw_nav_item_model';

export const NAV_ITEMS_DATA: Array<SwNavItemModel> = [
  { name: 'Home',
  	route: '/Home' },
  { name: 'Offer',
    route: '/Offer',
  	children: [
      { name: 'Prices',
      	route: '/Prices' },
      { name: 'Samples',
        route: '/Samples' }
    ]
  },
  { name: 'About',
    route: '/About',
    children: [
      { name: 'Us',
        route: '/Us' },
      { name: 'Projects',
        route: '/Projects' },
      { name: 'Skills',
        route: '/Skills' }
    ]
  },
  { name: 'Contact',
    route: '/Contact' }
];

import {Injectable} from 'angular2/core';
import {NAV_ITEMS_DATA} from '../data/mock_nav_data';


@Injectable()
export class NavService {
	getNavData() {
		return Promise.resolve(NAV_ITEMS_DATA);
	}
}

import {Component, OnInit} from 'angular2/core';
import {
ROUTER_DIRECTIVES
} from 'angular2/router';
import {SwNavItemCmp} from './sw-nav-item/sw_nav_item';
import {SwNavItemModel} from '../../../models/sw_nav_item_model';
import {NavService} from '../../../services/nav_service';

@Component({
  selector: 'sw-nav',
  templateUrl: './components/shared/sw-nav/sw_nav.html',
  styleUrls: ['./components/shared/sw-nav/sw_nav.css'],
  providers: [NavService],
  directives: [ROUTER_DIRECTIVES, SwNavItemCmp]
})
export class SwNavCmp implements OnInit {
  public items: Array<SwNavItemCmp> = [];

  constructor(private _navService: NavService) {
  }

  ngOnInit(): any {
    this.getNavData();
  }

  getNavData() {
      this._navService.getNavData().then((navData: Array<SwNavItemModel>) => {
          console.log(navData);
          console.log(Object.keys(navData));
          this.addItems(navData);
      });
  }

  addItem(name: string, route: string, children?: Array<SwNavItemModel>) {
    console.log();
    console.log('name: ' + name);
    console.log('route: ' + route);
    console.log('children: ' + children);
    if(children) {
      let childrenItems: Array<SwNavItemCmp> = [];
      console.log('childrenItems: ' + childrenItems);
      children.forEach((child) => {
        console.log('child: ' + child);
        childrenItems.push(new SwNavItemCmp(child.name, child.route, null));
        console.log('childrenItems: ' + childrenItems);
      });
      this.items.push(new SwNavItemCmp(name, route, childrenItems));
      console.log('Items: ' + this.items);
    } else {
      this.items.push(new SwNavItemCmp(name, route, null));
      console.log('Items: ' + this.items);
    }
  }

  addItems(itemsArray: Array<SwNavItemModel>) {
    console.log('ItemsArray: ' + itemsArray);
    itemsArray.forEach((item) => {
      console.log('item: ' + item);
      item.children ? this.addItem(item.name, item.route, item.children) : this.addItem(item.name, item.route, null);
    });
    console.log('Items: ' + this.items);
  }
}

import {Component, Input} from 'angular2/core';
import {ROUTER_DIRECTIVES} from 'angular2/router';


@Component({
  selector: 'sw-nav-item',
  templateUrl: './components/shared/sw-nav/sw-nav-item/sw_nav_item.html',
  styleUrls: ['./components/shared/sw-nav/sw-nav-item/sw_nav_item.css'],
  directives: [ROUTER_DIRECTIVES]
})
export class SwNavItemCmp {
	@Input() items: Array<SwNavItemCmp>;
  name: string;
  route: string;
  children: Array<SwNavItemCmp> = [];
  constructor(name: string, route: string, children?: Array<SwNavItemCmp>) {
    this.name = name;
    this.route = route;
    this.children = children;
  }
}

constructor(name: string, route: string, children?: Array) {...

throw error TS2314: Generic type 'Array<T>' requires 1 type argument(s).

//////////////////////////////////////////////////////////////

Now I have this:

sw_nav.ts

...
export class SwNavCmp implements OnInit {
  public items: Array<SwNavItemCmp> = [];
  ...
}

sw_nav.html

    <nav>
    <ul class="main-menu">
        <li *ngFor="#item of items">
            <sw-nav-item [items]="item.children"></sw-nav-item>
        </li>
    </ul>
</nav>

questions: -Should I pass whole item insted of item.children?

sw_nav_item.ts

import {Component, Input, Inject, Injectable} from 'angular2/core';
import {ROUTER_DIRECTIVES} from 'angular2/router';

@Component({
  selector: 'sw-nav-item',
  templateUrl: './components/shared/sw-nav/sw-nav-item/sw_nav_item.html',
  styleUrls: ['./components/shared/sw-nav/sw-nav-item/sw_nav_item.css'],
  directives: [ROUTER_DIRECTIVES]
})
@Injectable()
export class SwNavItemCmp {
  @Input() items: Array<SwNavItemCmp>;

  name: string;
  route: string;
  children: Array<SwNavItemCmp>;

  constructor(name, route, @Inject(SwNavItemCmp) children: Array<SwNavItemCmp>) {
    this.name = name;
    this.route = route;
    this.children = children;
  }
}

questions: -How should constructor looks like? I think it's invalid. -How to pass data from input to constructor? -Should I use Injector.resolveAndCreateChild() to assing children items?

sw-nav-item.html

???

questions: -How to render it recursive? I want to render all sw-nav-item be itself.

And main questions: -Where should I put var injector = Injector.resolveAndCreate(... provide(...), and how should it looks like? -If I have wrong structure or concept. How to do it right way? I mean recursive components creation and rendreing.

Upvotes: 3

Views: 7353

Answers (1)

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657348

Update

-How should constructor looks like? I think it's invalid.

The constructor should list the arguments you want to get passed in by Angulars dependency injection (DI). DI can pass values where it has a provider registered in bootstrap (bootstrap(AppComponent, [SomeProvider, ...]))

-How to pass data from input to constructor? -Should I use Injector.resolveAndCreateChild() to assing children items?

I don't know what you mean by "input" or "children items" here. You don't need Injector.resolveAndCreateChild()

-How to render it recursive? I want to render all sw-nav-item be itself.

I don't understand the question. How is that related to the constructor?

-Where should I put var injector = Injector.resolveAndCreate(... provide(...),

As mentioned above, you don't need that.

and how should it looks like? -If I have wrong structure or concept. How to do it right way? I mean recursive components creation and rendreing.

You don't need the constructor for this. If you want to pass data from parent to children use binding

<!-- in parent component -->
<some-element [someInput]="someValueFromParent">

@Component({
   selector: 'child-component',
})
export class ChildComponent {
  @Input() someInput;

  constructor() {
    // here Angular hasn't yet assigned the `someValueFromParent`
  }

  ngOnInit() [
    // here or in event handlers I can access `someInput` and
    // `someValueFromParent` is assigned
  }
}

Original

The name and route parameters have no providers.

constructor(name: string, route: string, children?: Array<SwNavItemCmp>) {

You can't have parameters in components constructors without telling DI what to pass in.

What's the purpose of these parameters?

Upvotes: 3

Related Questions