Angular service not passing form data after routing - html

New to Angular and I feel like there's just an obvious mistake I am missing, code-wise.
I'm trying to follow the tutorial here: https://youtu.be/CUAHJxWGia0
I have one component to create/add an employee's ID called CreateEmployee.
On submission, it should route to a component to list all employees (ListEmployees).
It's using employee.service.ts.
When I click submit (before or without routing), it correctly logs the employee input to the console on CreateEmployee.
The problem is that when routing to the second component, ListEmployees, my new entry is not displayed at all, and only my test data is displayed.
I've made sure EmployeeService is included in my app.module as well.
create-employee.ts:
import { Component, OnInit } from '#angular/core'
import { FormControl, FormBuilder, NgForm } from '#angular/forms'
import { EmployeeService } from 'app/services/employee.service'
import { Router } from '#angular/router'
import { Employee } from 'app/shared/employee.model'
#Component({
selector: 'app-create-employee',
template: ` <form class="" [formGroup]="employeeForm" (ngSubmit)="saveEmployee()">
<div class="form-control">
<app-input
#memberID
name="memberID"
label="Member ID"
formControlName="memberID"
placeholder="Member ID"
></app-input>
</div>
<div><button type="submit" class="">Save</button></div>
</form>
{{ employeeForm.value | json }}
`,
styleUrls: ['./create-employee.component.scss'],
})
export class CreateEmployeeComponent implements OnInit {
employeeForm: any
constructor(private fb: FormBuilder, private _employeeService: EmployeeService, private _router: Router) {}
employee: Employee = {
memberID: null,
}
ngOnInit(): void {
this.employeeForm = this.fb.group({
memberID: new FormControl(''),
})
this.employee = this.employeeForm.get('memberID').value
}
saveEmployee() {
this._employeeService.save(this.employee)
console.log(this.employeeForm.get('memberID').value)
// this._router.navigate(['employee-list'])
}
}
list-employee.ts
import { Component, OnInit } from '#angular/core'
import { Employee } from 'app/shared/employee.model'
import { EmployeeService } from 'app/services/employee.service'
#Component({
selector: 'app-list-employees',
template: `<div *ngFor="let employee of employees">
<div class="">
{{ employee.memberID }}
</div>
</div> `,
styleUrls: ['./list-employees.component.scss'],
})
export class ListEmployeesComponent implements OnInit {
employees: Employee[] = []
constructor(private _employeeService: EmployeeService) {}
ngOnInit(): void {
this.employees = this._employeeService.getEmployees()
}
}
employee.service.ts
import { Injectable } from '#angular/core'
import { Employee } from 'app/shared/employee.model'
#Injectable({
providedIn: 'root',
})
export class EmployeeService {
listEmployees: Employee[] = [{ memberID: '1' }, { memberID: '2' }]
constructor() {}
getEmployees(): Employee[] {
return this.listEmployees
}
save(employee: Employee) {
this.listEmployees.push(employee)
}
}

Related

Angular and Typescript Sending Post Request

I have a simple page with angular and typescript with just 1 button and 1 text field. I want to make a post request to a link that posts the string written in text box.
my button html:
<a class="button-size">
Add Customer
</a>
and button ts file:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'customer-button123',
templateUrl: './blabla',
styleUrls: ['./clacla']
})
export class AddCustomerButtonComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
text box html:
<mat-form-field>
<input matInput placeholder="Customer Name">
</mat-form-field>
text box ts file:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'customer-text-field',
templateUrl: './blabla2',
styleUrls: ['./clacla2']
})
export class CustomerTextFieldComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
and simple wrapper page html is:
<div class="input-label">
<mg-customer-text-field></mg-customer-text-field>
</div>
<div>
<mg-customer-button123></mg-customer-button123>
</div>
How can i send a post reques to link localhost8080/admin/addCustomer ?
If you hosting your front end at port: 4200 (default Angular port serve) and you want to send a request to http://localhost8080/admin/addCustomer, you will need a proxy configuration. You can see right here for more info: https://itnext.io/angular-cli-proxy-configuration-4311acec9d6f
You use the HttpModule
I use a service to separate http requests.
Example
import { Component, OnInit } from '#angular/core';
import { ApiService } from '../../services/api.service';
#Component({
selector: 'customer-button123',
templateUrl: './blabla',
styleUrls: ['./clacla']
})
export class AddCustomerButtonComponent implements OnInit {
data: any;
results: any;
constructor(private apiService: ApiService) { }
ngOnInit() {
}
getDataFromApi() {
this.apiService.getData(this.data).subscribe(results => {
this.results = results;
});
}
ApiService
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class ApiService {
apiUrl: string = environment.apiUrl;
constructor(private http: HttpClient) {}
getData(data): any {
return this.http.get(`http://localhost:8080/api/get-data`);
}
html
<div class="input-label">
<mg-customer-text-field [(ngModel)]="data"></mg-customer-text-field>
</div>
<div>
<mg-customer-button123 (click)="getDataFromApi()"></mg-customer-button123>
</div>

Display data from json array using angular4

I am new to angular so please help me. I have an api returning an array of objects containing name, place id.
I need to display this in different cards on my html page, the cards being a widget.
in the parent component under the ngOnInit() section how do I access this json data and loop through the array in order to display it on my page as different cards?
Thank you in advance.
import { Component, OnInit } from '#angular/core';
import {HttpClient} from '#angular/common/http';
import { Observable } from 'rxjs/observable';
#Component({
selector: 'app-home-page',
templateUrl: './home-page.component.html',
styleUrls: ['./home-page.component.css']
})
export class HomePageComponent implements OnInit {
showSplash = true
//public events: any = [];
events = [];
constructor(private http : HttpClient) { }
ngOnInit() {
this.showSplash = true
this.http.get("/events").subscribe(data => {
console.log("EVENTS ARE: ", data);
this.events = data;
console.log(this.events)
})
}
ngAfterViewInit(){
setTimeout(() => {
this.showSplash = false
}, 3000);
}
}
This will get you the events you want.
import { Component, OnInit, OnDestroy } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Subscription } from 'rxjs';
#Component({
selector: 'app-home-page',
templateUrl: './home-page.component.html',
styleUrls: ['./home-page.component.css']
})
export class HomePageComponent implements OnInit, OnDestroy {
showSplash = true
events = [];
subscription: Subscription;
constructor(private http: HttpClient) {}
ngOnInit() {
this.subscription = this.http.get("/events").subscribe(data => {
this.events = data;
this.showSplash = false;
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
You will have to implement a Child Component(EventComponent probably with the selector app-event) that will accept an event object as an #Input property. Then in your HomePageComponent Template, you can loop through the events like this:
<div *ngFor="let event of events">
<app-event [event]="event"></app-event>
</div>
Alternatively:
You can use the async pipe in your HomePageComponent's Template to avoid manually unsubscribing from the Observable Subscription. Your HomePageComponent Class code will change to:
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-home-page',
templateUrl: './home-page.component.html',
styleUrls: ['./home-page.component.css']
})
export class HomePageComponent implements OnInit {
events$;
constructor(private http: HttpClient) {}
ngOnInit() {
this.events$ = this.http.get("/events");
}
}
And then in HomePageComponent's Template:
<div *ngFor="let event of events$ | async">
<app-event [event]="event"></app-event>
</div>
Here's how your EventComponent would look like in this case:
import { Component, Input, OnChanges } from '#angular/core';
#Component({
selector: 'app-event',
templateUrl: './event.component.html',
styleUrls: ['./event.component.css']
})
export class EventComponent implements OnChanges{
#Input() event;
ngOnChanges() {
this.events$ = this.http.get("/events");
}
}

Firebase Cloud Firestore can not load data

When I open web data is show but I change component and come back this component data not show.It show no item. I check log but not run to ngOnIt. ngOnIt run on web strat or web reload.
this is stock.service.ts
import { Injectable } from '#angular/core';
import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from 'angularfire2/firestore';
import { Observable } from 'rxjs/Observable';
import { Stock } from './stock.model';
#Injectable()
export class StockService {
stocksCollection: AngularFirestoreCollection<Stock>;
stocks: Observable<Stock[]>;
constructor(public afs: AngularFirestore) {
this.stocks = this.afs.collection('stocks').valueChanges();
}
getStock(){
return this.stocks;
}
}
stock.component.ts
import { Component, OnInit, Input } from '#angular/core';
import { ActivatedRoute,Params } from '#angular/router';
import { StockService } from '../shared/stock.service';
import { Stock } from '../shared/stock.model';
import { Brands } from '../shared/brand';
import { Subscription } from 'rxjs/Subscription';
#Component({
selector: 'app-stock',
templateUrl: './stock.component.html',
styleUrls: ['./stock.component.css']
})
export class StockComponent implements OnInit {
stocks: Stock[];
brand: Brands;
sub: Subscription;
brand_name: string;
constructor(
private stockService: StockService,
private router: ActivatedRoute
) { }
ngOnInit() {
this.stockService.getStock().subscribe(stocks => {
console.log(stocks);
this.stocks = stocks;
});
this.sub = this.router.params.subscribe(params =>{
this.brand_name = params['brand'];
});
console.log('Brand : '+this.brand_name);
}
}
and stock.component.html
<div *ngIf="stocks != null || stocks?.length > 0 ; else noStocks" >
<ul *ngFor="let item of stocks" class="collection">
<li class="collection-item " >{{item.name}} | {{item.brand}} | {{item.price}}</li>
</ul>
</div>
<ng-template #noStocks>
<p>no item</p>
</ng-template>
I don't know where code is mistake. Thank you for answer.
Don't load inside the constructor of your service, move it inside your method
constructor(public afs: AngularFirestore) {
}
getStock(){
this.stocks = this.afs.collection('stocks').valueChanges();
return this.stocks;
}

Parent / Child component communication angular 2

I am failing to implement action button in child_1 component but the event handler is in sub child component child_2 as shown in the following code:
app.component.html (Parent Html)
<div style="text-align:center">
<h1>
Welcome to {{title}}!
</h1>
<app-navigation></app-navigation> <!-- Child1-->
</div>
app.component.html (Parent Component)
import { Component } from '#angular/core';
import { ProductService } from './productservice';
import {Product} from './product';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
title = 'MobileShirtShoeApp';
}
app.module.ts (Main Module)
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { HttpModule } from '#angular/http';
import { Product } from './product';
import { ProductService } from './productservice';
import { AppComponent } from './app.component';
import { NavigationComponent } from './navigation/navigation.component';
import { DataTemplateComponent } from './data-template/data-template.component';
#NgModule({
declarations: [AppComponent,NavigationComponent,DataTemplateComponent],
imports: [BrowserModule,HttpModule],
providers: [ProductService],
bootstrap: [AppComponent]
})
export class AppModule { }
navigation.component.html (Child 1 HTML)
<fieldset>
<legend>Navigate</legend>
<div>
<button (click)="loadMobiles()">Mobiles</button> <!--Child_1 Action-->
</div>
<app-data-template></app-data-template>
</fieldset>
navigation.component.ts (Child 1 Component.ts)
import { Component, OnInit } from '#angular/core';
import { ProductService } from '../productservice';
import {Product} from '../product';
import {DataTemplateComponent} from '../data-template/data-template.component';
#Component({
selector: 'app-navigation',
templateUrl: './navigation.component.html',
styleUrls: ['./navigation.component.css']
})
export class NavigationComponent implements OnInit {
error: string;
productArray: Product[];
constructor(private myService: ProductService){
this.myService = myService;
}
dataTemplateComponent: DataTemplateComponent = new DataTemplateComponent(this.myService);
ngOnInit() {
}
loadMobiles() {
return this.dataTemplateComponent.loadMobiles();
}
}
data-template.component.html (Child 2 HTML) (NOT DISPLAYING DATA)
<fieldset>
<legend>Requested Data</legend>
Welcome
<div>
<ul>
<li *ngFor="let product of productArray">
{{product.id}} {{product.name}} {{product.price}}
<img src="{{product.url}}">
</li>
</ul>
</div>
</fieldset>
data-template.component.ts (Child 2 Component) (Contains Product service calling code)
import { Component} from '#angular/core';
import {Product} from '../product';
import {ProductService} from '../productservice';
#Component({
selector: 'app-data-template',
templateUrl: './data-template.component.html',
styleUrls: ['./data-template.component.css']
})
export class DataTemplateComponent {
error: string;
productArray: Product[];
constructor(private productService: ProductService) {
this.productService = productService;
}
loadMobiles(){
let promise = this.productService.fetchMobiles();
promise.then(productArr => {
return this.productArray = productArr;
}).catch((err) => {
this.error = err;
});
}
}
ProductService.ts
import 'rxjs/add/operator/toPromise';
import {Http, HttpModule} from '#angular/http';
import {Injectable} from '#angular/core';
import {Product} from './product';
#Injectable()
export class ProductService{
http: Http;
constructor(http: Http){
this.http = http;
console.log(http);
}
fetchMobiles(): Promise<Product[]>{
let url = "https://raw.githubusercontent.com/xxxxx/Other/master/JsonData/MobileData.json";
return this.http.get(url).toPromise().then((response) => {
return response.json().mobiles as Product[];
}).catch(this.handleError);
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error);
return Promise.reject(error.message || error);
}
}
Sorry if the code bothers you. So basically i am failing to display service data in child_2.html when an action made in child_1.html.The service working fine and name is ProductService which uses Product.ts as an object to get the data in JSON format. Any kind of help is appreciated.
This doesn't work because the DataTemplateComponent you're instantiating in app-navigation isn't the same instance of DataTemplateComponent as the one on the page. It's a brand new one that you instantiated and that isn't bound to the page at all. What you're trying to achieve is component communication. Specifically, parent / child component communication. There are a number of ways to do this, the cleanest and most flexible / extensible way is with a shared service pattern. Basically, you declare a service with an observable in it that you inject into both services and one updates the observable while the other is subscribed to it, like this:
#Inject()
export class MyComponentCommunicationService {
private commSubject: Subject<any> = new Subject();
comm$: Observable<any> = this.commSubject.asObservable();
notify() {
this.commSubject.next();
}
}
Then provide this service, either at the app module or possibly at the parent component depending on needs then in app navigation:
constructor(private commService: MyComponentCommunicationService) {}
loadMobiles() {
this.commservice.notify();
}
and in data template:
constructor(private commService: MyComponentCommunicationService, private productService: ProductService) {}
ngOnInit() {
this.commSub = this.commService.comm$.subscribe(e => this.loadMobiles());
}
ngOnDestroy() { this.commSub.unsubscribe(); } // always clean subscriptions
This is probably a little unneccessary since you already have the product service there. You could probably just move the load mobiles logic into the product service and have that trigger an observable that the data template service is subscribed to, and have the nav component call the load mobile method on the product service, but this is just meant to illustrate the concept.
I'd probably do it like this:
#Inject()
export class ProductService {
private productSubject: Subject<Product[]> = new Subject<Product[]>();
products$: Observable<Product[]> = this.productSubject.asObservable();
loadMobiles() {
this.fetchMobiles().then(productArr => {
this.productSubject.next(productArr);
}).catch((err) => {
this.productSubject.error(err);
});
}
}
then nav component:
loadMobiles() {
this.myService.loadMobiles();
}
then data template:
ngOnInit() {
this.productSub = this.productService.products$.subscribe(
products => this.productArray = products,
err => this.error = err
);
}
ngOnDestroy() { this.productSub.unsubscribe(); } // always clean subscriptions

Show related product for perticular Pincode using service provider in angular2

I want to create a single page application without use of routing,that will show when i give input for pincode,it will show the product for that pincode using service and injection.i am a bit confuse to create it.
Here is my product.service.ts
import { Injectable } from '#angular/core';
import { Product } from './product';
#Injectable()
export class ProductService {
private products: Product[] = [
new Product('10', 'schezwan rice', 'with schezwan sauce tasty', 'http://www.foodinnrestaurant.com/images/stories/virtuemart/product/prodt_328.jpg'),
Product('11', 'Summer salad', 'looks tasty and healthy', 'http://images.media- allrecipes.com/userphotos/250x250/00/39/70/397065.jpg')
];
constructor() { }
getProducts() {
return this.products;
}
}
I make a class for product
In product.ts
export class Product {
constructor (public pin: number, public name: string, public description: string, public imagePath: string) {
}
}
Here is my product-group component
<div class="row">
<div class="col-xs-12">
<ul class="list-group">
<li *ngFor="let product of products" [product]="product"(click)="onSelected(product)"></li>
</ul>
</div>
</div>
here is my product-group.ts code
import { Component, OnInit, Input } from '#angular/core';
import { Product } from '../product';
#Component({
selector: 'ps-product-group',
templateUrl: './product-group.component.html',
styleUrls: ['./product-group.component.css']
})
export class ProductGroupComponent implements OnInit {
#Input() product: Product;
constructor() { }
ngOnInit() {
}
}
Here is my pincode.ts code
import { Component, OnInit, EventEmitter, Output } from '#angular/core';
import { Product } from '../product';
import { ProductService } from '../product.service';
#Component({
selector: 'ps-pincode',
templateUrl: './pincode.component.html',
styleUrls: ['./pincode.component.css'],
providers: [ProductService]
})
export class PincodeComponent implements OnInit {
products: Product[] =[];
#Output() productSelected = new EventEmitter<Product>();
ngOnInit() {
}
onSelected(product: Product) {
this.productSelected.emit(product);
}
}
here is my pincode html component
<div class="container">
<div class="form-group">
<input type="number" class="form-control" placeholder="Enter your pincode">
</div>
<button type="submit" class="btn btn-default" (click)="onSelected(products)" >Submit</button>
</div>