3

I have a form which allows user to create an account, once the user clicks on submit button the user is navigated to another page with the details of that account they have create. The issue I am having is passing that object to the details view.

For example here is my component for the form,

import {Component, OnInit, OnDestroy, Input} from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import {Customer} from "../model/customer";
import {Router } from '@angular/router';
import {CustomerService} from "../service/customer.service";
import {CustomerProfileComponent} from "../customer-profile/customer-profile.component";

@Component({
  selector: 'app-new-customer',
  templateUrl: './new-customer.component.html',
  styleUrls: ['./new-customer.component.css']
})
export class NewCustomerComponent implements OnInit {

  @Input() customer: Customer;

  //this is only dev data do not use this in prod
  private countries = [];
  private customerSources = [];
  private secondarySources =[];

  //Create the forum group
  public newCustomerForm: FormGroup;
  public submitted: boolean; // keep track on whether form is submitted

  constructor(private fb: FormBuilder, public customerService: CustomerService,private router: Router) {

    this.countries = [
      {value:'UK'},
      {value:'Germany'},
      {value:'Turkey'},
      {value:'Italy'}
      ];

    this.customerSources = [
      {value: 'Through a friend or colleague (not a Client)'},
      {value: 'Through an existing Client'},
      {value: 'Direct Sales (e.g. cold call, direct mail, email)'},
      {value: 'Web Search e.g. Google'}
    ];

    this.secondarySources = [
      {value: '1st Hire'},
      {value: 'A Test Client With A Long Business Name'},
      {value: 'Abbigail West'}
    ];
  }

  ngOnInit() {
    this.newCustomerForm = this.fb.group({
      id:[''],
      company_name: ['', [<any>Validators.required, <any>Validators.minLength(5)]],
      vat:[''],
      address:[''],
      country:[''],
      first_name:[''],
      surname:[''],
      phone:[''],
      email:['',[<any>Validators.required, <any>Validators.minLength(5)]],
      customer_sources:[''],
      secondary_sources:['']
    });
  }

here is my form html,

 <form [formGroup]="newCustomerForm" novalidate (ngSubmit)="saveNewCustomer(newCustomerForm.value, newCustomerForm.valid)">
    <section>
      <aside>
        <p>Once you've added your new <b>Client</b>, you can come back and allow them access to view their <b>Invoices</b> &amp; <b>Payments</b> - they can also make <b>Payments</b> via Paypal if you have it enabled.</p>
      </aside>


      <input type="hidden" name="id"  formControlName="id"/>

      <h4>New Client Details</h4>
      <md-input-container>
        <input mdInput type="text" name="company_name" placeholder="Customer Name" formControlName="company_name" />
        <small [hidden]="newCustomerForm.controls.company_name.valid || (newCustomerForm.controls.company_name.pristine && !submitted)">
          Customer Name is required (minimum 5 characters).
        </small>
      </md-input-container>

      <md-input-container>
        <input mdInput type="text" name="vat"  placeholder="VAT Number" formControlName="vat"/>
      </md-input-container>

      <md-input-container>
        <input mdInput type="text" name="address"  placeholder="Address" formControlName="address" />
      </md-input-container>

      <md-select placeholder="Country" name="country" formControlName="country" >
        <md-option *ngFor="let country of countries" [value]="country.value" >
          {{country.value}}
        </md-option>
      </md-select>

      <h4>Your Primary Contact</h4>
      <div class="left-column">
        <md-input-container>
          <input mdInput type="text" name="first_name"  placeholder="First Name" formControlName="first_name" />
        </md-input-container>
      </div>

      <div class="left-column">
        <md-input-container>
          <input mdInput type="text" name="surname"  placeholder="surname" formControlName="surname" />
        </md-input-container>
      </div>

      <div class="clearfix"></div>

      <div class="left-column">
        <div class="left-column">
          <md-input-container>
            <input mdInput type="text" name="phone"  placeholder="Phone" formControlName="phone"/>
          </md-input-container>
        </div>
      </div>

      <div class="right-column">
        <div class="left-column">
          <md-input-container>
            <input mdInput type="text" name="email"  placeholder="Email" formControlName="email"/>
            <small [hidden]="newCustomerForm.controls.email.valid || (newCustomerForm.controls.email.pristine && !submitted)">
              Email is required (minimum 5 characters).
            </small>
          </md-input-container>
        </div>
      </div>

      <div class="clearfix"></div>
      <h4>Customer Source</h4>
      <div class="left-column">
        <md-select placeholder="How were you introduced to this Client?" formControlName="customer_sources">
          <md-option *ngFor="let cs of customerSources" [value]="cs.value" >
            {{cs.value}}
          </md-option>
        </md-select>
      </div>

      <div class="right-column">
          <md-select placeholder="Which Client introduced you?" formControlName="secondary_sources">
            <md-option *ngFor="let ss of secondarySources" [value]="ss.value" >
              {{ss.value}}
            </md-option>
          </md-select>
      </div>
      <div class="clearfix"></div>
    </section>

    <aside>
      <div class="right-aside">
        <button type="submit" class="cancel">Cancel</button>
        <button type="submit" class="save">Save</button>
      </div>
      <div class="clearfix"></div>
    </aside>
    </form>

Customer service is in my app.module. Here I am saving the data and moving the user on to the new page.

  saveNewCustomer(customer: Customer, isValid: boolean){
    if(isValid){
      this.submitted = true; // set form submit to true
      this.customerService.saveNewCustomer(customer)
        .subscribe(
          res => this.customer,
          error => console.log(<any>error)
        );

      this.router.navigateByUrl('/earning/customers/profile');
    }
  }


} 

And this is the component I would like the customer object to use so it be present in the view.

import {Component, OnInit, Input} from '@angular/core';
import {Customer} from "../model/customer";
import {NewCustomerComponent} from "../new-customer/new-customer.component";

@Component({
  selector: 'app-customer-profile',
  templateUrl: './customer-profile.component.html',
  styleUrls: ['./customer-profile.component.css'],
  providers:[NewCustomerComponent]
})
export class CustomerProfileComponent implements OnInit {

 @Input() customer: Customer;

  constructor() {
    console.log(this.customer);
  }

  ngOnInit() {
  }

}

<main>
  <header>
    <h4>&nbsp;</h4>
    <h1><strong><i></i>Customer profile</strong></h1>
    </header>
  <article>
    <section>
      <p></p>

      <p>
        {{customer}}
      </p>
      </section>
    </article>
  </main>

But customer is undefined in the CustomerProfileComponent. I am not sure what I am doing wrong. if anyone can point me in the right direction would be much appreciated.

Update to include service class based on suggestion

import { Injectable } from '@angular/core';
import {Http, Response, Headers, RequestOptions} from '@angular/http';
import {CookieService} from "angular2-cookie/services/cookies.service";

import {Observable, Subject} from "rxjs";
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import {Customer} from "../model/customer";


@Injectable()
export class CustomerService {

  private csrfToken;
  private newCustomerUrl = "/earning/customers/new";
  private customer = new Subject<Object>();

  customer$ = this.customer.asObservable();

  constructor(public http: Http, private cookieService: CookieService) {
    this.getCsrfToken();
  }

  getCsrfToken(){
    this.csrfToken = this.cookieService.get("PLAY_SESSION").substring(this.cookieService.get("PLAY_SESSION").indexOf("csrfToken"));
  }

  saveNewCustomer(customer:Customer): Observable<Customer>{

    let headers = new Headers({
      'Content-Type':'application/json'
    });

    let options = new RequestOptions({ headers: headers });

    return this.http.post(this.newCustomerUrl+"?"+this.csrfToken, customer, options) // ...using post request
      .map((res:Response) => res.json()) // ...and calling .json() on the response to return data
      .catch(this.handleError); //...errors if any
  }

  private handleError (error: Response) {
    return Observable.throw('Internal server error: ' + error);
  }

  emitCustomer(customer) {
    this.customer.next(customer);
  }


}
4
  • post the related template code Commented Mar 3, 2017 at 11:39
  • Either paste your html code, or set up a service which communicates between components a shown here: angular.io/docs/ts/latest/cookbook/… Commented Mar 3, 2017 at 11:50
  • @AvinashRaj I have pasted in my html code. Thanks
    – Limpep
    Commented Mar 3, 2017 at 13:28
  • @CodeRatchetI have pasted in my html code. Thanks
    – Limpep
    Commented Mar 3, 2017 at 13:29

1 Answer 1

3

As mentioned a shared service would be a good option. the following example is sharing the Object between the components via service:

Your service:

public sharedCustomer = {};

And the component, after that you have received your customer from the api, push the customer to the service:

  this.customerService.saveNewCustomer(customer)
    .subscribe(res => {
       this.customer = res;
       this.customerService.sharedCustomer = this.customer;
       this.router.navigateByUrl('/earning/customers/profile');
    });
  }

Notice that I'm emitting the customer inside the subscription, as well as the navigation, to ensure that the customer gets stored in the service properly, as well as not navigating away from page before that.

Then in your detail page:

ngOnInit() {
  this.customer = this.customerService.sharedCustomer;
}
8
  • I seem to be getting undefined, on my profile page ngOnInit() { this.customerService.customer$.subscribe(customer => { this.customer = customer; }); console.log(this.customer); } there is data coming back from the API that is of type Customer object
    – Limpep
    Commented Mar 3, 2017 at 14:48
  • I have also updated my question to include my service class.
    – Limpep
    Commented Mar 3, 2017 at 14:55
  • Have you checked that you are indeed receiving a customer in your subscription, that it is not undefined? :)
    – AVJT82
    Commented Mar 3, 2017 at 15:05
  • I am indeed getting back an object here a screenshot ibb.co/hbjSBF
    – Limpep
    Commented Mar 3, 2017 at 15:12
  • 1
    So new-customer-component is the component that the user post the form data to the service component which post the data to the server, so once the data is posted the user is moved on to the profile page of that customer they have just created.
    – Limpep
    Commented Mar 3, 2017 at 15:40

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.