0

I'm passing a values from one component to the other:

paquete-detalle.component.ts

nombre: string;
precio: number;

ngOnInit() {
const id = this.activatedRoute.snapshot.paramMap.get('id');
  this.fs.getPaqueteObject(id).valueChanges().subscribe(paquete => {
    this.nombre = paquete.nombre;
    this.precio = paquete.precio;
  });
}

paquete-detalle.component.html

{{nombre}} {{precio}} //All good with these values, if they are printed.
<app-reserva [precio]="precio" [nombre]="nombre"></app-reserva>

Then in reserva.component.ts I have the following:

@Input() precio: number;
@Input() nombre: string;

constructor( private fs: FirebaseService, private fb: FormBuilder, ) {
    this.forma = fb.group ({
      nombre: [ this.nombre ],
      precio: [ this.precio ],
    });
   }

ngOnInit() {
    console.log(this.precio, this.nombre);
  }

This is where I try to save it in a reactive form but I get null ( undefined in the console) as a result of this.price and this.name.

However, in reserva.component.html if the values are printed:

 <div class="text-center">
    <h4>{{nombre}}</h4>
    <p>Desde: USD {{precio}} / persona</p>
 </div>

What is the correct way to pass the values between components?

Paco Zevallos
  • 2,165
  • 7
  • 30
  • 68
  • Setting the form in the constructor doesn't look quite right to me... – mottosson Jun 10 '19 at 13:17
  • for `[precio]="precio"` is precio defined in the parent? – Andrew Allen Jun 10 '19 at 13:19
  • What about (remove the brackets []) – mottosson Jun 10 '19 at 13:22
  • At the construction time the inputs haven't been set. You need to move that to the ngOnInit method to make sure that your child component already received the inputs from the parent. What is going with your console.log is that at the OnInit phase there's no value for precio and nombre, but you already created a binding in the constructor, so when the component already receives the inputs then change detection will run and your template will update with the proper values. – Gonzalo Muro Jun 10 '19 at 13:40
  • I think people are ignoring the fact that if you are getting undefined in the console when calling `console.log(this.precio, this.nombre);` inside `ngOnInit` then this suggests `precio` and `nombre` have not been set in the parent – Andrew Allen Jun 10 '19 at 13:50

4 Answers4

4

Your component initialization logic should live in ngOnInit(). Since your parent component has some asynchronous logic in its own ngOnInit() you'll then want to prevent your app-reserva component from being created until you have all the data you need.

paquete-detalle.component.ts

nombre: string = null;
precio: number = null;

ngOnInit() {
const id = this.activatedRoute.snapshot.paramMap.get('id');
  this.fs.getPaqueteObject(id).valueChanges().subscribe(paquete => {
    this.nombre = paquete.nombre;
    this.precio = paquete.precio;
  });
}

paquete-detalle.component.html

{{nombre}} {{precio}} //All good with these values, if they are printed.
<app-reserva *ngIf="precio && nombre" [precio]="precio" [nombre]="nombre"></app-reserva>    

reserva.component.ts

@Input() precio: number;
@Input() nombre: string;

constructor( private fs: FirebaseService, private fb: FormBuilder, ) {
}

ngOnInit() {
  this.forma = fb.group ({
    nombre: [ this.nombre ],
    precio: [ this.precio ],
  });
  console.log(this.precio, this.nombre);
}

This answer here does a good job explaining the difference between constructor and ngOnInit.

The reason your child component is still initializing an empty form is because your child component was created before the parent component finished executing the callback in this.fs.getPaqueteObject(id).valueChanges().subscribe(). With this approach your reserva.component.ts won't be rendered until your parent component finishes getting all the data the child needs.

This is just one approach, you can also look into OnChanges to make your child component react when the @Input() values change or Resolvers to load data into the route before the component loads.

spots
  • 2,483
  • 5
  • 23
  • 38
  • Thanks @spots this has not solved the problem. I'm still printing on the console in ngOnInit these values but I get null – Paco Zevallos Jun 10 '19 at 14:50
  • I missed that your parent component has some async behavior. I updated my answer to account for that. – spots Jun 10 '19 at 15:21
  • Excellent @spots this helped a lot, thanks for explaining the approach. I have made it work but with a small adjustment in your code: `*ngIf =" precio && nombre "` this worked for me. If I leave it in `*ngIf =" null! == precio && null! == nombre "` I kept getting `null`. By the way there is a typo in the *ngIf. – Paco Zevallos Jun 10 '19 at 15:52
1

The values passed by Input() are not available in the constructor since they are not yet passed to the child. Consider building your form in the ngOnInit() method and you should be good to go !

GregRbs
  • 36
  • 1
  • Thanks @GregRbs this has not solved the problem. I'm still printing on the console in `ngOnInit` these values but I get null – Paco Zevallos Jun 10 '19 at 14:44
0

Stackblitz - https://stackblitz.com/edit/angular-9d3bu4-so-56527061

Make sure the parent has defined the precio and nombre that you are passing (via one way binding) when you use <app-reserva [precio]="precio" [nombre]="nombre"></app-reserva>

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular';

  precio = 24.50;
  nombre = "boots"
}

app.component.html

<app-reserva [precio]="precio" [nombre]="nombre"></app-reserva>
Andrew Allen
  • 6,512
  • 5
  • 30
  • 73
  • Yes, those values are already defined in `reserva-paquete.component.ts` everything is fine with those values. I have edited my answer so you can see the code I added. I do not understand why those values are not printed in `reserva.component.ts` – Paco Zevallos Jun 10 '19 at 14:41
0

Try to remove the brackets from the component and use the interpolation syntax {{ }}:

<app-reserva precio="{{precio}}" nombre="{{nombre}}"></app-reserva>

https://stackblitz.com/edit/angular-jwhf87?file=src%2Fapp%2Fapp.component.html

mottosson
  • 3,283
  • 4
  • 35
  • 73