Unable to calculate Total in my shopping-cart - javascript

I Have created a shopping cart with 2 components(Productlist and cart list). when I click on the 'add to cart' button in the product list it is successfully moving into the service file and from the service file to 'cart list' but Total was showing undefined. Please help me to solve this cart Total issue.
Product-list.ts file
import { Component, OnInit } from '#angular/core';
import { ProductService } from '../../../service/product.service';
import { CartService } from '../../../service/cart.service';
#Component({
selector: 'app-product-list',
templateUrl: './product-list.component.html',
styleUrls: ['./product-list.component.css']
})
export class ProductListComponent implements OnInit {
Productlist = [];
constructor(private productservice: ProductService,
private cartservice: CartService) {
this.Productlist = this.productservice.send()
}
ngOnInit(): void {
}
saveproduct(item) {
this.cartservice.get(item)
}
}
cart service file
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class CartService {
cartproducts = [{Name: 'Mobile', Price: 13000, Qty: 1}]
constructor() { }
send() {
return this.cartproducts
}
get(items) {
this.cartproducts.push(items)
console.log(this.cartproducts)
}
}
cart list file
import { Component, OnInit, ɵConsole, ɵɵNgOnChangesFeature } from '#angular/core';
import { CartService } from '../../../service/cart.service';
#Component({
selector: 'app-cart',
templateUrl: './cart.component.html',
styleUrls: ['./cart.component.css']
})
export class CartComponent implements OnInit {
cartlist = [];
Total: number;
constructor( private cartservice: CartService) {
this.cartlist = this.cartservice.send()
console.log(this.cartlist);
console.log(this.Total);
}
ngOnInit() {
this.cartlist.forEach((_e: any) => {
this.Total += (_e.qty * _e.price);
});
}
}

When the Total property has been created, it is undefined by default until you assign it a value. You do assign a value to it in the ngOnInit but you calculate on an undefined value, so it returns undefined as well. Give Total a default value like so:
...
Total: number = 0;
...
Also the code you put in ngOnInit to calculate the Total, would be better placed in a get property. This way, Total will always be calculated when it's requested instead of pre-rendered and only calculated once. In that case your code would look like:
get Total(): number {
let value = 0;
this.cartlist?.forEach((_e: any) => {
value += (_e.qty * _e.price);
});
return value;
}

Related

displaying items from DB using Angular 12

the Item file
component file
the data service file
when I test my code with console log statements it says data from service is undefined
import { Component, OnInit } from '#angular/core';
import { Item } from '../item';
import { DataService } from '../data.service';
#Component({
selector: 'app-shopping-item',
templateUrl: './shopping-item.component.html',
styleUrls: ['./shopping-item.component.css'],
providers: [DataService]
})
export class ShoppingItemComponent implements OnInit {
shoppingItemList: Item[] = [];
constructor(private dataservice: DataService){}
getItems(){
this.dataservice.getShoppingItems()
.subscribe(items =>{
this.shoppingItemList.push(items),
console.log('data from dataservice '+ this.shoppingItemList[0].itemName);
})
}
addItem(form: any){
console.log(form)
}
ngOnInit(): void {
this.getItems();
}
}
If you are receiving an array from the API call, then you need to either assign it directly to the property (1) or destructure the array into the property (2)
Currently I guess you are pushing an array inside an array, which might lead to undefined error!
import { Component, OnInit } from '#angular/core';
import { Item } from '../item';
import { DataService } from '../data.service';
#Component({
selector: 'app-shopping-item',
templateUrl: './shopping-item.component.html',
styleUrls: ['./shopping-item.component.css'],
providers: [DataService]
})
export class ShoppingItemComponent implements OnInit {
shoppingItemList: Item[] = [];
constructor(private dataservice: DataService){}
getItems(){
this.dataservice.getShoppingItems()
.subscribe(items =>{
this.shoppingItemList = items; // solution 1
// this.shoppingItemList.push(...items); // solution 2
console.log('data from dataservice '+ this.shoppingItemList[0].itemName);
})
}
addItem(form: any){
console.log(form)
}
ngOnInit(): void {
this.getItems();
}
}

Angular does not rerender on Input() change

Whatever i do angular does not detect change on talks array. I have a handleSubmit function to send the toolbar. Toolbar use it to send the changes to parent from input field.
My app.component.ts file
import { Component, Type, OnChanges, SimpleChanges } from '#angular/core';
import { getResponse } from '../api/API';
declare module '../api/API' {
export interface NlpAPI {
getResponse(data: any): Promise<any>;
}
}
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnChanges {
talks: string[];
title: string;
ngOnChanges(changes: SimpleChanges): void {
console.log(changes);
}
constructor() {
this.talks = [];
this.title = 'Talks';
}
ngOnInit() {
this.talks.push('Welcome to ProjectX! How can I help you?');
this.talks.push('I am a chatbot. I can help you with your queries.');
}
handleSubmit(data: any): void {
this.talks.push(data.talk);
}
messageResponse() {
// #ts-ignore: Object is possibly 'null'.
const x = document.getElementById('txt').value;
// #ts-ignore: Object is possibly 'null'.
document.getElementById('output').innerHTML =
'Your message is ' + '"' + x + '"';
}
}
My app.component.html
<!-- Toolbar -->
<app-custom-toolbar [handleSubmit]="handleSubmit"></app-custom-toolbar>
<!-- Highlight Card -->
<app-text-area [talksFromUser]="talks" [title]="title"></app-text-area>
<!-- Bottombar -->
<router-outlet></router-outlet>
My text-area.component.ts file
import { Component, Input, OnChanges, SimpleChanges } from '#angular/core';
#Component({
selector: 'app-text-area',
templateUrl: './text-area.component.html',
styleUrls: ['./text-area.component.css'],
})
export class TextAreaComponent implements OnChanges {
#Input() talksFromUser: string[] = [];
#Input() title: string = '';
constructor() {}
ngOnChanges(changes: SimpleChanges): void {
console.log(changes);
}
}
My text-area.component.html
<div class="main-text-area">
<div *ngFor="let item of talksFromUser">{{ item }}</div>
</div>
custom-toolbar.component.ts file
import { Component, Input, OnInit } from '#angular/core';
import { NgForm } from '#angular/forms';
#Component({
selector: 'app-custom-toolbar',
templateUrl: './custom-toolbar.component.html',
styleUrls: ['./custom-toolbar.component.css'],
})
export class CustomToolbarComponent implements OnInit {
talks: string[] = [];
#Input() handleSubmit!: (args: any) => void;
constructor() {}
ngOnInit(): void {}
onSubmit(f: NgForm) {
this.handleSubmit(f.value);
f.resetForm();
}
}
I tried also
this.talks = [...this.talks, data.talk]
Thank you all.
There are two issues in your code:
First one, you are calling handleSubmit("string") (so data is a string), but you are pushing data.talk, which is undefined (so talks will be [undefined, undefined, ...]). To fix it, use data:
handleSubmit(data: any): void {
this.talks.push(data); // use "data" instead of "data.talk"
}
Second one, you are using a AppComponent method into CustomToolbarComponent class. You need to keep the this scope of AppComponent. Also, you should use arrow functions:
handleSubmit = (data: any): void => {
this.talks.push(data);
}

Retrieving the next item in an array by index in Angular 11

I have a list of employees in a JSON object in my service.ts file. It will be moved to a DB eventually. I know this is not the place for it. It's just for dev purposes. I am able to retrieve the employees by clicking on it and displaying them in a dynamic view component.
However, I want to be able to see the next employee on a button click without having to always go back to the main list. I am able to retrieve the index and increment the index on click. I just can't get the route to display the data for that index.
The HTML is pretty basic a simple button with a click method. The Service file looks like this:
import {HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Employee } from '../models/employee.models';
#Injectable({
providedIn: 'root'
})
export class EmployeesService {
private listEmployees: Employee[] = [...regular json object...];
constructor() { }
getEmployees(): Employee[] {
return this.listEmployees;
}
getEmployee(id: number): Employee {
return this.listEmployees.find(e => e.id === id);
}
}
And my employee.component.ts file
import { ActivatedRoute } from '#angular/router';
import { EmployeesService } from './../../../services/employees.service';
import { Component, OnInit } from '#angular/core';
import { Employee } from 'src/app/models/employee.models';
import { Router } from '#angular/router';
#Component({
selector: 'employee',
templateUrl: './employee.component.html',
styleUrls: ['./employee.component.scss']
})
export class EmployeeComponent implements OnInit {
employee: Employee;
employees: Employee[];
index: number;
private _id: number;
constructor(
private _route: ActivatedRoute,
private _router: Router,
private _employeeService: EmployeesService
) { }
ngOnInit() {
this.employees = this._employeeService.getEmployees();
for ( this.index = 1; this.index < this.employees.length + 1; this.index++ ) {
this._route.paramMap.subscribe(params => {
this._id = +params.get('id')
console.log('this index:', this.index);
this.employee = this._employeeService.getEmployee(this._id);
});
}
}
viewNextEmployee() {
if( this.index < this.employees.length ){
this.index = this.index++;
console.log('this index:', this.index);
this._router.navigate(['/team', this._id])
} else {
this.index = 1;
}
}
}
I'm sorry, I can't really reproduce a working code. So many dependencies.

Data not passing through with route in Angular 6

I have a application with a table of cars:
This is my code:
Carcomponent.html
<tbody>
<tr *ngFor="let car of allCars; index as carId" \>
<td [routerLink]="['/cars', carId]">{{car.carId}}</td>
<td>{{car.brand}}</td>
<td>{{car.model}}</td>
<td>{{car.color}}</td>
<td>{{car.topSpeed }}</td>
</tr>
</tbody>
I have register the route like this:
{ path: 'cars/:carId', component: CardetailsComponent }
And this is my CarDetails.ts file:
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { CarVM } from '../viewmodels/car-vm';
import { CarService } from '../services/car.service';
#Component({
selector: 'app-cardetails',
templateUrl: './cardetails.component.html',
styleUrls: ['./cardetails.component.css']
})
export class CardetailsComponent implements OnInit {
car: any;
carList: any;
constructor(private route: ActivatedRoute, private carservice: CarService) { }
ngOnInit() {
this.route.paramMap.subscribe(params => {
this.car = params.get('carId');
});
}
getCarList() {
this.carList = new CarVM();
this.carservice.getCarById(this.carList.carId).subscribe((res: any) => {
this.carList = res.data;
console.log(this.carList)
})
}
}
And on my Cardetails.html I want to show the selected car like this:
<h2>Car Details</h2>
<div *ngIf="car">
<h3>{{ car.brand }}</h3>
<h4>{{ car.model }}</h4>
<p>{{ car.color }}</p>
</div>
The routing is working fine and fetching the cars is working. Now I want to select one car and see the brand, model, color on the next page. I use a viewmodel for this:
export class CarVM {
CarId: number;
Brand: string;
Model: string;
Color: string;
TopSpeed: number;
}
How can I see the selected car on the next page?
I have followed this tutorial:
https://angular.io/start/routing
Ok, you seem to be bit confused. In cardetails component you want to process carId from route parameters and use it to get car details. You can either get them from server, or have the service return already loaded details of all cars.
Let's say we are trying to make it happen getting the first way, it might look like this:
import { map, switchMap } from 'rxjs/operators';
ngOnInit() {
this.getCar();
}
private getCar(): void {
this.route.paramMap.pipe(
map(params => params.get('carId')),
switchMap(carId => {
return this.carservice.getCarById(carId);
})
).subscribe(
res => {
this.car = res;
console.log('#My car:', this.car);
}
);
}
First, you'll get the carId from route.paramMap, map it using rxjs map, then use switchMap to call you carservice.getCarById(carId) and have it return Observable to which you can subscribe. This should do the trick. Don't forget to properly map it/create CarVM object from it.
The problem is, you don't have CarVM object properly on CardetailsComponent. You are only getting carId into CarVM here: this.car = CarVM[+params.get('carId')];
First you need to create CarVM properly with your class variables. And the you can call your index.
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { CarVM } from '../viewmodels/car-vm';
#Component({
selector: 'app-cardetails',
templateUrl: './cardetails.component.html',
styleUrls: ['./cardetails.component.css']
})
export class CardetailsComponent implements OnInit {
car: any;
carList: any;
constructor(private route: ActivatedRoute) { }
ngOnInit() {
this.route.paramMap.subscribe(params => {
this.car = params.get('carId');
});
}
getCarList(){
this.carList = new CarVM();
//call your service here to fill your carList variable and once you get car list, you will be able to access variable using with your index (this.car).
}
}

Ionic How to Pass variable to firebase equalTo method

I have already managed to fetch data form firebase.problem is when i'm going to filter data according to the id it doesn't work.
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { AngularFireDatabase, AngularFireList ,} from 'angularfire2/database';
import { Observable } from 'rxjs'
import { query } from '#angular/core/src/render3';
import { Key } from 'protractor';
class postview {
constructor(public title) { }
}
#Component({
selector: 'app-news-view',
templateUrl: './news-view.page.html',
styleUrls: ['./news-view.page.scss'],
})
export class NewsViewPage implements OnInit {
id: string;
public books: AngularFireList<postview[]>;
itemlol: Observable<any>;
posts: Observable<any[]>;
constructor(private route: ActivatedRoute , db: AngularFireDatabase) {
let idp :string = this.id;
this.posts = db.list('Posts' ,ref => {
return ref.orderByChild('Post_Id').equalTo(idp)
}).valueChanges();
// this.itemlol= db.object('Posts').valueChanges();
}
ngOnInit() {
this.id = this.route.snapshot.paramMap.get('id');
console.log(this.id);
console.log(this.posts);
}
}
in the section return ref.orderByChild('Post_Id').equalTo(idp) I need to pass variable in equalTo(). It should change according to the user instructions
Example
equalTo(01)
equalTo(02)
This is my firebase database:
The constructor is called before ngOnInit so the value for this.id will be undefined at the time of the query.
You should get the Parameters in the constructor
this.id = this.route.snapshot.paramMap.get('id');
let idp :string = this.id;
this.posts = db.list('Posts' ,ref => ref.orderByChild('Post_Id').equalTo(idp) ).valueChanges();

Categories

Resources