4

Im building basic Todo App in angular2 when I click add button to send data from parent to child using input I get No provider for string! (child->string), and no data displayed only button at the child class is shown, what does it mean

here is parent component:

@Component({
selector : 'parent-component',
directives : [child],
template : `
<h1 class= "text-center">ToDo App</h1>
<div class = "form-group">
<lable>Task</lable>
<input type = "text" class = "form-control" #task>
<lable>Detail</lable>
<input type = "text" class = "form-control" #detail >
<button type = "submit" class  = "btn btn-default" 
(click) = "addtask(task,    detail)">Add Task</button>


<child-component *ngFor = "#todo of Array" [taskobject] = "todo">
Loading... </child-component>
</div>

`
})
class parent{
//taskobj : {task : string, details : string, id:  number};
Array : child[];
id : number;

constructor(){

    //i want this to initialize asa parent create
    this.Array = [];
}

addtask(task : HTMLInputElement, detail : HTMLInputElement){
    // this.taskobj.task= task.value;
    // this.taskobj.details = detail.value;
   this.id = Date.now();
    // this.array.push();

    this.Array.push(new child(task.value, detail.value, this.id ));
    console.log(Array)
    task.value = '';
    detail.value = '';

}

And this is child component:

@Component({

selector : 'child-component',
inputs : ['taskobject'],
//outputs : ['objectsend'],
template : `
  {{taskobject.task}}
  {{taskobject.details}}
  <button type = "button" class = "btn btn-default" 
  (click) = "deletetask()">Delete</button>
  <button type = "button" class = "btn btn-defualt" 
  (click) = "updatetask()">Update</button>

  `
  })
class child{

//we are creating a instance just as configured as child component 
task : string;
detals : string;
id : number;
//array : any[];

constructor(task : string, detail : string, id : number){
    this.task = task;
    this.detals = detail;
    this.id = id;
}

}
blackHawk
  • 6,047
  • 13
  • 57
  • 100

2 Answers2

3

You got an error since Angular2 instantiate the child class by its own and try to inject in it the parameters you define at its constructor level. There is no associated provider for them...

Otherwise if you want to reference children components from parent ones, you could leverage the @ViewChild decorator to reference the child component from the parent one by injection:

import { Component, ViewChild } from 'angular2/core';  

(...)

@Component({
  selector: 'my-app',
  template: `
    <h1>My First Angular 2 App</h1>
    <child></child>
    <button (click)="submit()">Submit</button>
  `,
  directives:[App]
})
export class AppComponent { 
  @ViewChild(SearchBar) searchBar:SearchBar;

  (...)

  someOtherMethod() {
    this.searchBar.someMethod();
  }
}

Here is the updated plunkr: http://plnkr.co/edit/mrVK2j3hJQ04n8vlXLXt?p=preview.

You can notice that the @Query parameter decorator could also be used:

export class AppComponent { 
  constructor(@Query(SearchBar) children:QueryList<SearchBar>) {
    this.childcmp = children.first();
  }

  (...)
}

Hope it helps you, Thierry

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • You mean i didn't define inputs in child component? – blackHawk Feb 02 '16 at 09:10
  • Oh sorry, I missed your `inputs` attribute... I used to use decorator for this ;-) I updated my answer accordingly – Thierry Templier Feb 02 '16 at 09:12
  • Your problem is linked to your child component constructor and the fact you instantiate the `child` class by hand... – Thierry Templier Feb 02 '16 at 09:13
  • By hand I instantiating the child class, how? – blackHawk Feb 02 '16 at 09:28
  • Here: `this.Array.push(new child(task.value, detail.value, this.id ));`, no? ;-) – Thierry Templier Feb 02 '16 at 09:29
  • Oh yes :) so what is the best way instead, I did this so that object inserted is the object of child in the array – blackHawk Feb 02 '16 at 09:46
  • In fact using an `ngFor` and using corresponding element as parameter of the sub component will do the same thing ;-) – Thierry Templier Feb 02 '16 at 09:49
  • Without array? Could you plunkr ;) – blackHawk Feb 02 '16 at 09:58
  • Here is a plunkr: https://plnkr.co/edit/0AZMqlu2gamjj1zTZbaV?p=preview ;-) Notice the use of the `concat` method instead of `push` to trigger change detection of Angular2 (http://stackoverflow.com/questions/35076907/angular-2-trouble-with-custom-components/35080334#35080334 - `slice` could also be used) – Thierry Templier Feb 02 '16 at 10:19
  • same problem : EXCEPTION: No provider for String! (child -> String) in [Arrayobj in parent] (changed the name from Array to Arrayobj) – blackHawk Feb 02 '16 at 11:13
  • In the plunkr I provided to you? According to the error message, I think that it remains some parameters in the constructor of the `child` component... – Thierry Templier Feb 02 '16 at 11:20
  • https://plnkr.co/edit/KNhred?p=info here is my plunkr, the error gone but no task or description displayed, onlu update and delete buttons shown – blackHawk Feb 02 '16 at 17:46
  • I guess that it's an issue related to change detection of Angular2. In fact you need to update the whole reference of your array. Updates in it won't be detected by Angular. You can have a look at my plunkr within the `addtask`: I used the `concat` method instead of the `push` one. To delete you need to leverage the `slice` method... Hope it's clear. See this answer for more details: http://stackoverflow.com/questions/35076907/angular-2-trouble-with-custom-components/35080334#35080334 – Thierry Templier Feb 02 '16 at 19:25
  • I think @Thierry thats not good idea to put anything that is expect to come should initialize in constructor of the definition class(because i dnt know when its gets initialized :P ) so i emptied constructor, now if Im taking data from form its coming to me in this form " input name = "tasks" #task class = "form-control" , meaning whole input tag, also local class variable is forcing it to be input elemet type when im doing this.task = task in addtask function because it cant assign a html element type to string – blackHawk Feb 02 '16 at 22:43
  • Oh i forgot task.value :D – blackHawk Feb 02 '16 at 23:01
1

Constructor parameters are resolved from DI providers specified in bootstrap(AppComponent, [SomeProvider, SomeOtherProvider, ...]);

Inputs are assigned automatically but only after the lifecycle call to ngOnInit().

@Component({
  selector : 'child-component',
  inputs : ['taskobject'],
  //outputs : ['objectsend'],
  template : `
    {{taskobject?.task}}
    <!-- use the safe-navigation operator ?. to avoid errors 
      when `taskobject` is not yet set
    -->
    {{taskobject?.details}}
    <button type = "button" class = "btn btn-default" 
    (click) = "deletetask()">Delete</button>
    <button type = "button" class = "btn btn-defualt" 
    (click) = "updatetask()">Update</button>
    `
})
class child {
  //we are creating a instance just as configured as child component 
  taskobject: any;
  task : string;
  detals : string;
  id : number;
  //array : any[];

  constructor() {
  }

  // when this callback is called the 
  // `taskobject` (from `inputs : ['taskobject'],`) 
  // is initialized 
  ngOnInit() {
    this.task = taskobject.task;
    this.detals = taskobject.detail;
    this.id = taskobject.id;
  }
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Could you provide useful link to understand your this sentence or explain here a little bit, "Constructor parameters are resolved from DI providers specified in bootstrap(AppComponent, [SomeProvider, SomeOtherProvider, ...]);" – blackHawk Feb 02 '16 at 09:29
  • http://blog.thoughtram.io/angular/2015/05/18/dependency-injection-in-angular-2.html, http://victorsavkin.com/post/126514197956/dependency-injection-in-angular-1-and-angular-2, http://www.syntaxsuccess.com/viewarticle/dependency-injection-in-angular-2.0, https://angular.io/docs/ts/latest/guide/dependency-injection.html – Günter Zöchbauer Feb 02 '16 at 09:31
  • I know the data coming from inputs is available to child class view/template(in my case taskobject), how can I teach child definition class about taskobject coming from parent through input, – blackHawk Feb 02 '16 at 09:37
  • That's what 'inputs' does. You have to pass inputs using template binding like `` – Günter Zöchbauer Feb 02 '16 at 09:39