Can't get value from radio button ionic 3 - javascript

I'm trying to make multiple choice quiz app with ionic but i confuse how to get score, i think i can get the selected value in radio button to making a score. but i dont understand how to get value from selected radio button in ionic with ngFor loop from database.
this is my html file
<ion-header>
<ion-navbar>
<ion-title>Quiz <ion-icon name="more" (click)="showMore($event)" style="float:right; cursor:pointer; width:20px;"></ion-icon></ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<div *ngFor="let item of items">
<p class="pertanyaan">{{ item.pertanyaan }} </p><br>
<form>
<div>
<input type="radio" name="jwb1" id="jwb1" value="A" [(ngModel)]="jawaban"/>
<label for="jwb1">{{ item.jawaban1 }}</label>
</div>
<div>
<input type="radio" name="jwb1" id="jwb2" value="B" [(ngModel)]="jawaban"/>
<label for="jwb2">{{ item.jawaban2 }}</label>
</div>
<div>
<input type="radio" name="jwb1" id="jwb3" value="C" [(ngModel)]="jawaban"/>
<label for="jwb3">{{ item.jawaban3 }}</label>
</div>
<div>
<input type="radio" name="jwb1" id="jwb4" value="D" [(ngModel)]="jawaban"/>
<label for="jwb4">{{ item.jawaban4 }}</label>
</div>
<br>
<br>
<br>
<br>
<br>
</form>
</div>
<button ion-button name="submit" ng-model="submit" (click)="konfirmasiKirim()">Submit</button>
</ion-content>
and this my ts file
import { Component } from '#angular/core';
import { IonicPage, NavController } from 'ionic-angular';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
import { NavParams } from 'ionic-angular/navigation/nav-params';
import { AlertController } from 'ionic-angular/components/alert/alert-controller';
#IonicPage()
#Component({
selector: 'page-quiz',
templateUrl: 'quiz.html',
})
export class QuizPage {
public username:any;
public jawaban:any;
public items : any = [];
constructor(public navCtrl: NavController,
public http : Http,
public navParams: NavParams,
public alertCtrl: AlertController)
{
}
ionViewDidLoad() {
this.username = this.navParams.get('username');
}
ionViewWillEnter()
{
this.load();
}
// Retrieve the JSON encoded data from the remote server
// Using Angular's Http class and an Observable - then
// assign this to the items array for rendering to the HTML template
load()
{
this.http.get('https://apifisika.000webhostapp.com')
.map(res => res.json())
.subscribe(data =>
{
this.items = data;
});
}
konfirmasiKirim()
{
let confirm = this.alertCtrl.create({
title: 'Kirim Jawaban?',
message: 'Hai '+this.username+' sudah yakin untuk kirim jawaban?',
buttons: [
{
text: 'Cek kembali',
handler: () => {
console.log('mengko');
}
},
{
text: 'Kirim Jawaban',
handler: () => {
// this.navCtrl.push(QuizPage);
alert(this.jawaban);
}
}
]
});
confirm.present();
}
}
In my database there are 10 question, So i need to get value from each question, for example number 1 i choose a, number 2 b, ... number 10 i choose d. And then i get all the value above to make a scoring.
Can someone help me to get selected value in radio button with *ngFor loop? pls

tweak the code of this.items = data; to be
this.items.forEach(item => {
item.isSelected = false;
});
and in your HTML do ngModel on this value like so:
<form>
<div *ngFor="let item of items">
<p class="pertanyaan">{{ item.pertanyaan }} </p>
<div>
<input type="radio" name="jwb{{ item.jawaban1 }}" id="jwb{{ item.jawaban1 }}" [(ngModel)]="item.isSelected"/>
<label for="jwb1">{{ item.jawaban1 }}</label>
</div>
</div>
</form>
and to display the results as a score of total:
<h3>{{ totalSelected() }}</h3>
and in your ts within your class add the following function:
totalSelected(){
return this.items.filter(item => return item.isSelected).length
}
That's it, I'm ready to tweak it for you if you want to calculate each selected answer passed on some certain condition and/or return a specific weight for the correct answer

Related

How would I go about binding form input from multiple child components to an array defined in a parent component?

I am trying to bind form input from multiple child components (item-input-component) to array itemList[] defined in a parent component (add-invoice-component). I want to take three inputs (itemName, quantity, price), create an Item object out of them, then output that Item object from item-input-component and add it to itemList[]. How can I do that ? Is that even possible ? And if not, what's a good solution ?
add-invoice-component.html
<form>
<div>
<h2>Items</h2>
<app-item-input *ngFor="let item of numArray"></app-item-input>
<button (click)="incrementNumOfItems()">Add Item</button>
</div>
</form>
add-invoice-component.ts
import { Component, ElementRef, OnInit, Renderer2 } from '#angular/core';
import { Item } from 'src/app/models/item';
#Component({
selector: 'app-add-invoice',
templateUrl: './add-invoice.component.html',
styleUrls: ['./add-invoice.component.css']
})
export class AddInvoiceComponent implements OnInit {
description!: string;
invoiceDate!: Date;
clientName!: string;
clientAddress!: string;
itemList!: Item[];
numOfItems: number = 2;
numArray: number[] = Array(2).fill(0).map((x,i)=>i);
constructor( private el: ElementRef) { }
ngOnInit(): void {
}
incrementNumOfItems() {
this.numOfItems++;
this.numArray = Array(this.numOfItems).fill(0).map((x,i)=>i);
}
removeItem() {
this.el.nativeElement.remove()
}
}
item-input-component.html
<div class="mb-3 row item">
<div class="col">
<label for="item-name" class="form-label">Item Name</label>
<input type="text" id="item-name" name="clientName" class="form-control">
</div>
<div class="col">
<label for="quantity" class="form-label">Quantity</label>
<input type="text" id="quantity" name="quantity" class="form-control">
</div>
<div class="col">
<label for="price" class="form-label">Price</label>
<input type="text" id="price" name="price" class="form-control">
</div>
<button (click)="removeItem()">Delete Item</button>
item-input-component.ts
import { Component, ElementRef, OnInit , Renderer2} from '#angular/core';
#Component({
selector: 'app-item-input',
templateUrl: './item-input.component.html',
styleUrls: ['./item-input.component.css']
})
export class ItemInputComponent implements OnInit {
itemName!: string;
quantity!: number;
price!: number;
constructor(private el: ElementRef) { }
ngOnInit(): void {
}
removeItem() {
this.el.nativeElement.remove()
}
}
Item.ts
export interface Item {
itemName: string,
quantity: number,
price: number
}
The question is about pass to your child component an object, to Delete you need use Output to comunicate with the parent
This object will be an object with properties: itemName, quantity and price -and the you use [(ngModel)] or a FormGroup -and you use ReactiveForms-
#Input()element:any
#Output() deleteItem:EventEmitter<any>:new EventEmitter<any>()
<input ... [(ngModel)]="element.clientName">
<input ... [(ngModel)]="element.quantity">
<input ... [(ngModel)]="element.price">
<button (click)="deleteItem.emit(null)">Delete Item</button>
Your parent
<app-item-input *ngFor="let item of list;let i=index"
[element]="list[i]"
(deleteItem)="removeItem(i)"
></app-item-input>
where
list:any[]=this.numArray.map(_=>({
clientName:'',
quantity:0,
price:0
}))
//see that removeItem remove one value of the array.
//**NOT** about your .html
removeItem(index:number) {
this.list.splice(index,1)
}
Using a FormArray is looks like
formGroup:FormGroup;
#Input('group') set _group(value)
{
this.formGroup=value as FormGroup
}
#Output() deleteItem:EventEmitter<any>:new EventEmitter<any>()
<form [formGroup]="fromGroup">
<input ... formControlName="clientName">
<input ... formControlName="quantity">
<input ... formControlName="price">
</form>
<button (click)="deleteItem.emit(null)">Delete Item</button>
And the parent
<app-item-input *ngFor="let item of listFormArray.controls;let i=index"
[group]="listFormArray.at(i)"
(deleteItem)="removeItem(i)"
></app-item-input>
listFormArray:FormArray[]=new FormArray(
this.numArray.map(_=>(new FormGroup({
clientName:new FormControl(null),
quantity:new FormControl(0),
price::new FormControl(0)
})))
)
removeItem(index:number) {
this.formArray.removeAt(index)
}
Looks like you're not familiar with Angular services, so here's an example to show you how it works.
Stackblitz: https://stackblitz.com/edit/angular-ivy-afppeb?file=src/app/item.service.ts
Here's a simple service to hold the items, it has add and delete methods
Item Service
#Injectable({ providedIn: 'root' })
export class ItemService {
itemList: Item[] = [];
addItem(item: Item) {
this.itemList.push(item);
}
deleteItem(index: number) {
this.itemList.splice(index, 1);
}
}
To access this service you just inject it via the constructor of any component:
Add Invoice Component
export class AddInvoiceComponent {
constructor(private itemService: ItemService) {}
get items() {
return this.itemService.itemList;
}
delete(index: number) {
this.itemService.deleteItem(index);
}
}
<app-item-input></app-item-input>
<h1>Items</h1>
<ng-container *ngFor="let item of items; index as i">
<pre>{{ item | json }}</pre>
<button (click)="delete(i)">Delete</button>
</ng-container>
And here's a simple way to convert the form data to an object
Item Input Component
export class ItemInputComponent {
formGroup = new FormGroup({
itemName: new FormControl(''),
quantity: new FormControl(0),
price: new FormControl(0),
});
constructor(private itemService: ItemService) {}
onSubmit() {
this.itemService.addItem(this.formGroup.getRawValue());
}
}
<h1>Input</h1>
<form [formGroup]="formGroup" (ngSubmit)="onSubmit()">
<div>
<label>Item Name:</label>
<input type="text" formControlName="itemName" />
</div>
<div>
<label>Quantity:</label>
<input type="number" formControlName="quantity" />
</div>
<div>
<label>Price:</label>
<input type="number" formControlName="price" />
</div>
<button type="submit">Submit</button>
</form>
You may want to do form validation as well, but this is just to show you how the service works.

Angular Reactive form set Multiselect Checkbox values

The form is having 1 textbox , 1 radio button and 1 multi select Checkbox The HTML template is like below
<form *ngIf="notificationSettings | async; else loading"
[formGroup]="notificationForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<div *ngFor="let option of notifyBackAlertOptions; let i=index">
<input type="checkbox" class="form-check-input" [value]="option.value" formControlName="notifyBackOptions" />
<label> {{option.name}} </label>
</div>
</div>
<div class="form-group">
<label for="notifyBackEmail">Where shall we send the alerts?</label>
<input type="email" class="form-control" formControlName="notifyBackEmail">
</div>
<div class="form-check" *ngFor="let option of discontinuedAlertOptions;">
<label>
<input formControlName="discontinuedOption" class="form-check-input"
type="radio"
name="discontinuedOption"
[value]="option.value" />
{{option.name}}
</label>
</div>
<div class="float-left">
<button class="btn btn-primary mr-1">Update</button>
</div>
</form>
<ng-template #loading>
Loading ---...
</ng-template>
The component is like below
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
export class NotifcationsComponent implements OnInit {
notificationSettings: Observable<NotificationSetting>;
notificationForm: FormGroup;
submitted = false;
notifyBackAlertOptions = [
{ name: 'Option 1', value: '1' },
{ name: 'Option 2', value: '2' },
{ name: 'Option 3', value: '3' },
{ name: 'Option 4', value: '4' }
];
discontinuedAlertOptions = [
{ name: 'Yes for any', value: '1' },
{name: 'Yes for all', value: '2' },
{ name: 'No', value: '3' }
];
constructor(private formBuilder: FormBuilder,private userService: UserService) { }
ngOnInit() {
this.getCurrentSettings();
this.notificationForm = this.formBuilder.group({
notifyBackEmail: [''],
discontinuedOption: [''],
notifyBackOptions: new FormArray([]),
});
}
getCurrentSettings(): void {
this.notificationSettings = this.userService
.getUserNotificationSettings()
.pipe(tap(data => {
console.log("GET")
this.notificationForm = this.formBuilder.group({
notifyBackEmail: new FormControl(data.notifyBackEmail),
discontinuedOption: new FormControl(data.discontinuedOption),
notifyBackOptions: new FormControl(data.notifyBackOptions)
});
console.log(this.notificationForm) //I can see the values are mapping correctly against notificationForm. Checkbox property ie notifyBackOptions value is coming as ["1", "2"] at this stage
}
));
//This code maps / sets the values of textbox and radio buttons correctly at page loading based on response from API. But not setting values for multiselect checkbox correctly.
//I can see all checkbox values are coming as selected. IN this case 4 checkbox values are selected
//How to set only the notifyBackOptions checkbox selected values marked as checked
}
// convenience getter for easy access to form fields in HTML page
get f() { return this.notificationForm.controls; }
onSubmit() {
this.submitted = true;
// stop here if form is invalid
if (this.notificationForm.invalid) {
return;
}
console.log(this.notificationForm.value);
}
}
The HTML is rendering correctly and capturing the values at form submission . At load time of the component i have to read the values from API endpoint and prefill form based on current settings
The JSON response from API endpoint is like below
{
notifyBackEmail: "email#email-domain.in"
notifyBackOptions: ["1","2"]
discontinuedOption: "1"
}
The existing implementation of getCurrentSettings() is setting values of radio and textbox correctly but not checkbox.
At present this is setting all values of checkbox as selected. How can i set the Checkbox values as selected based on response form API with help of model binding
Since you are handling with array of values, you need to create array of formControl instead of single formControl. Try something like this:
Try this:
notificationForm: FormGroup;
getCurrentSettings(): void {
this.notificationSettings = this.userService
.getUserNotificationSettings()
.pipe(
tap(data => {
const notifyBackOptions = data.notifyBackOptions;
const notificationControls = this.notifyBackAlertOptions.map(
item => new FormControl(notifyBackOptions.includes(item.value))
);
this.notificationForm = this.formBuilder.group({
notifyBackEmail: [''],
discontinuedOption: [''],
notifyBackOptions: this.formBuilder.array(notificationControls)
});
})
);
}
Then in HTML You need to add formArrayName directive to sync with FormGroup
<form [formGroup]="notificationForm" (ngSubmit)="onSubmit()">
<div class="form-group" formArrayName="notifyBackOptions">
<div *ngFor="let option of notifyBackOptionsArr.controls; let i=index">
<input [formControlName]="i" type="checkbox" class="form-check-input" />
<label> {{notifyBackAlertOptions[i].name}} </label>
</div>
</div>
<div class="form-group">
<label for="notifyBackEmail">Where shall we send the alerts?</label>
<input
type="email"
class="form-control"
formControlName="notifyBackEmail"
/>
</div>
<div class="form-check" *ngFor="let option of discontinuedAlertOptions;">
<label>
<input
formControlName="discontinuedOption"
class="form-check-input"
type="radio"
name="discontinuedOption"
[value]="option.value"
/>
{{option.name}}
</label>
</div>
<div class="float-left">
<button class="btn btn-primary mr-1">Update</button>
</div>
</form>
Working Example

ERROR Error: Cannot find control with path:

I am leveraging Angular 4's FormBuilder and FormGroup class to create a Form. The form's content is supplied by a GET call with the Questions and Answers structured via JSON format.
Dabbling with my localhost, I see the following error from my web console on page load:
Could anyone with Angular Forms expertise correct this implementation and explain where I went wrong?
Web Console indicates this node from the HTML is causing it:
<fieldset [formGroupName]="i">
For sake of brevity, I'm just providing the bare-bone snippets only down below. Let me know if you need more details.
HTML component:
<form id="form-clinicalscreener" [formGroup]="clinicalForm" (submit)="submitScreenerForm(clinicalForm)" novalidate>
<div formArrayName="Questions">
<div class="section" *ngFor="let tab of clinicalQuestionsResults; let i = index;">
<h2 class="form-title">{{tab.DisplayText}}</h2>
<div>
<div class="form-group" *ngFor="let question of tab.Questions">
<fieldset [formGroupName]="i">
<label>{{question.DisplayText}}</label>
<input type="hidden" formControlName="QuestionId" value="{{question.Id}}" data-value="{{question.Id}}">
<div [ngSwitch]="question.AnswerType">
<div *ngSwitchCase="'Radio'" class="form-group-answers">
<div class="radio" *ngFor="let answer of question.Answers">
<input type="radio"
formControlName="AnswerId"
value="{{answer.Id}}"
data-value="{{answer.Id}}"
class="radio-clinicalscreener">
<label class="label-answer">
<span class="label-answer-text">{{answer.DisplayText}}</span>
</label>
</div>
</div>
<div *ngSwitchCase="'DropDown'" class="form-group-answers">
<select formControlName="AnswerId" class="form-control">
<option value="{{answer.Id}}" data-value="{{answer.Id}}" *ngFor="let answer of question.Answers">{{answer.DisplayText}}</option>
</select>
</div>
</div>
</fieldset>
</div>
</div>
</div>
</div>
<div class="text-center">
<button class="btn btn-screener" type="submit" [disabled]="!clinicalForm.valid">Submit</button>
</div>
TypeScript component:
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormBuilder } from '#angular/forms';
#Component({
selector: '',
templateUrl: '',
styleUrls: ['']
})
export class FormComponent implements OnInit {
// Our model driven form.
clinicalForm: FormGroup;
// Screener Data from API call to be used by view in for loop.
clinicalQuestionsResults: any;
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
// Let's get Clinical Screener metadata.
this.loadClinicalScreener();
// Initialize the form here.
this.clinicalForm = this.formBuilder.group({
Questions: this.formBuilder.array([
this.initQuestions()
])
});
}
private initQuestions() {
// initialize our Questions
return this.formBuilder.group({
QuestionId: [''],
AnswerId: ['']
});
}
private loadClinicalScreener() {
// An AJAX call from a forkJoin() to return the JSON payload, then I assign it to a local object, screenerResponse.
let screenerResponse: any = data[0];
this.clinicalQuestionsResults = screenerResponse.Result.Tabs;
console.log('Here is the metadata for Clinical Screener --->', this.clinicalQuestionsResults);
}
}

Angular 2 select default value not working after selecting non-empty value

I am trying to set form validation for Angular 2 application i.e 'submit' button must be disabled when nothing selected in 'select' field. First time it was working well. But when I change the value, close the pop-up and re-open the same pop-up the default value is disappearing and submit also enabled. Please help me regarding this.
Code is:
<form #form="ngForm">
<div class="form-group" [class.has-error] = "adminError">
<label class="control-label" for="selectedValue">Select admin to be removed<span class="red-star">*</span>:</label>
<select class="form-control" [(ngModel)]="selectedValue" name="selectedValue" [ngModelOptions]="{standalone: true}" required>
<option color="grren" [ngValue]="admin" selected disabled>Select</option>
<option *ngFor="let admin of admins" [ngValue]= "admin.qlid">{{admin.name}} ({{admin.qlid}})</option>
</select>
</div>
<table width="80%">
<tr><td><button type="submit" class="btn btn-primary" [disabled]="form.invalid" (click)="removeAdmin(selectedValue)" data-dismiss="modal">Submit</button></td>
<td><button id="close3" type="button" class="btn btn-default" data-dismiss="modal">Close</button></td></tr>
</table>
<pre>Form Valid: {{form.valid | json}}</pre>
And the screen shots:
Respected Typescript file is:
import { Component } from '#angular/core';
import { AdminService } from '../../services/admin.service';
import { Admin } from '../../../Admin';
#Component({
moduleId: module.id,
selector: 'admins',
templateUrl: 'admin.component.html',
styleUrls: ['users.component.css']
})
export class AdminComponent {
constructor(private adminService:AdminService){
console.log("admin service initiated.");
}
admins: Admin[];
qlid: string;
selectedValue: string;
ngOnInit(){
console.log("admin service ngonit");
this.adminService.getAdmins()
.subscribe(admins => {
console.log("subscribe called");
this.admins = admins;
this.setPage(1);
});
}
refresh(){
this.adminService.getAdmins()
.subscribe(admins => {
console.log("subscribe called");
this.admins = admins;
});
}
removeAdmin(qlid){
this.adminService.removeAdmin(qlid)
.subscribe(data => {
this.refresh();
});
}
}

Angular 2 Passing form data to another component

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> & <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> </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);
}
}
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;
}

Categories

Resources