Zxcid
Zxcid

Reputation: 57

How to display forms submit in another component in Angular 8?

I'm learning Angular and I was trying to display a submitted form data in a different component than the one the form actually is.

So that's how I set up my app: I built the form in a component, created a user model, created a service that should provide cross component interaction and created an output component. The structure looks like this:

app-component folder

app.component.html,ts,css; app.module etc. files

home-form.component folder

home-form.component.hmtl,ts,css files

output-component folder

output.component.html,ts,css files

shared folder

user-module.ts, user-data.service.ts

That's my code so far:

that's my user model

export class User {
    public name: string;
    public surname: string;
    public gender: string;
    public email: string;

    constructor(name: string, surname: string, gender: string, email: string) {
      this.name = name;
      this.surname = surname;
      this.gender = gender;
      this.email = email;
    }
  }

HTML of form component

<div class="container">
  <form class="mt-5" (ngSubmit)="onSubmit()" #myForm="ngForm">
    <div class="row d-flex justify-content-center">

      <div class="col-md-6">
        <label for="name">Name</label>
        <input 
          type="text" 
          id="name" 
          class="form-control" 
          placeholder="start typing here..." 
          ngModel 
          name="name"
          required
          #name="ngModel">
        <span class="help-block text-danger" *ngIf="!name.valid && name.touched">*Please, enter a valid name</span>
      </div>

      <div class="col-md-6">
        <label for="surname">Surname</label>
        <input 
          type="text" 
          id="surname" 
          class="form-control" 
          placeholder="start typing here..." 
          ngModel 
          name="surname"
          required
          #surname="ngModel">
          <span class="help-block text-danger" *ngIf="!surname.valid && surname.touched">*Please, enter a valid surname</span>
      </div>

      <div class="col-md-6 mt-2">
        <label for="gender">Gender</label>
        <div class="form-check form-check-inline d-block">
          <input 
              class="form-check-input" 
              type="radio" 
              name="gender" 
              id="maleGender" 
              value="male" 
              ngModel
              required>
          <label class="form-check-label" for="inlineRadio1">Male</label>
        </div>
        <div class="form-check form-check-inline">
          <input 
            class="form-check-input" 
            type="radio" 
            name="gender" 
            id="femaleGender" 
            value="female" 
            ngModel
            required>
          <label class="form-check-label" for="inlineRadio2">Female</label>
        </div>
      </div>

      <div class="col-md-6 mt-2">
        <label for="email">E-mail</label>
        <input 
          type="email" 
          id="email" 
          class="form-control" 
          placeholder="start typing here..." 
          ngModel 
          name="email"
          required
          email
          #email="ngModel">
          <span class="help-block text-danger" *ngIf="!email.valid && email.touched">*Please, enter a valid e-mail</span>
      </div>

      <div class="mt-5">
        <button 
          type="submit" 
          class="btn btn-primary"
          [disabled]="!myForm.valid">Submit</button>
      </div>

    </div>
  </form>
</div>

TS file of that component

import { Component, OnInit, ViewChild, } from '@angular/core';
import { userDataService } from '../shared/user-data.service';
import { NgForm } from '@angular/forms';
import { User } from '../shared/user.model';

@Component({
  selector: 'app-home-form',
  templateUrl: './home-form.component.html',
  styleUrls: ['./home-form.component.css'],
  providers: [userDataService]
})

export class HomeFormComponent implements OnInit {


 @ViewChild('myForm', { static: false }) userForm: NgForm;    
  constructor(private userData: userDataService) {}    
  ngOnInit() {}

  onSubmit(){
    const newUser = new User(this.userForm.value['name'], this.userForm.value['surname'], this.userForm.value['gender'], this.userForm.value['email']);
    this.userData.addUser(newUser);
  }
}

then the user-data service

import { User } from './user.model';
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable()

export class userDataService {

    private myUser = new Subject<User>();
    myUserObservable = this.myUser.asObservable();

    addUser(user: User){
        this.myUser.next(user);
        //console.log(user);      
    }
}

and until here I still can log the object user with all the data submitted in the form.

that's the ts file of the comonent that should output the user. What am I doing wrong here?

import { Component, OnInit, OnDestroy } from '@angular/core';
import { userDataService } from '../shared/user-data.service';
import { User } from '../shared/user.model';

@Component({
  selector: 'app-user-profile',
  templateUrl: './user-profile.component.html',
  styleUrls: ['./user-profile.component.css'],
  providers: [userDataService]
})
export class UserProfileComponent implements OnInit, OnDestroy {
  user: User;


  constructor(private userData: userDataService) {}

  ngOnInit() {
    this.userData.myUserObservable.subscribe(
      (user: User) => {
        this.user = user;
        console.log(user);
      }
    );
  }

  ngOnDestroy(){

  }
}

ngOnDestroy is implemented to unsubscribe. the console.log is just a way to test if the data arrives, I wanted to display the data via string interpolation. Something like that

<div class="container">
<div class="row">
    <div class="col-md-12">
        <h3>You've created your profile!</h3>
        <p>Name: {{ user.name }}</p>
        <p>Surname: {{ user.surname }}</p>
        <p>Gender: {{ user.gender }}</p>
        <p>E-mail: {{ user.email }}</p>
    </div>
</div>

I would really appreciate any help and suggestion cause I'm really stuck here. Thank you all!

Upvotes: 1

Views: 2432

Answers (1)

Vitalii Ilchenko
Vitalii Ilchenko

Reputation: 598

The problem is that you inject two different instances of userDataService - one for each component.

  1. Remove providers: [userDataService] from your components decorators. You can read more about it at Official Angular documentation: Limiting provider scope with components

So, your Component decorators should look like that:

@Component({
  selector: 'app-home-form',
  templateUrl: './componentname.html',
  styleUrls: ['./componentname.css']
})
  1. The Injactable decorator of your userDataService should look like this

    @Injectable({ providedIn: 'root' }) export class userDataService { ....

In this case your service will be injected as a singleton to any of your components (this injectable should be provided in the 'root' injector, which will be the application-level injector in most apps.)

Upvotes: 1

Related Questions