how to get queryParams in subscribe from resolver - html

here is my ngOnInit (i am getting the data from a resolver)-
ngOnInit() {
const products = this.route.snapshot.data['users'] as IProductInterface[];
this._products = products.map((product) => new Product(product));
}
my getter -
public getProduct() {
return this._products;
}
here is how im displaying data on html -
<ng-container *ngFor="let product of getProduct()">
<span class="productInfo__title">{{ product.getTitle() }}</span>
</ng-container>
i would like to change that to subscribe because i want that to update whenever im changing the query. how can i do that? thanks

import { ActivatedRoute, Data } from '#angular/router';
....
....
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route.data.subscribe((data: Data) => {
const products = data['users'] as IProductInterface[];
this._products = products.map((product) => new Product(product));
})
}

Related

Angular Trouble Emptying Array

Hell, I have an e-commerce application in which I am trying to empty the shopping cart after payment is successful, no matter what I have tried the array will not empty. I have tried cartItems.length = 0,
cartItems = [] as well as splice. I must be missing something. Code snippet below I will walk you through it.
This is my Model
import { Product } from './product';
export class CartItem {
id: number;
productId: number;
productName: string;
qty: number;
price: number;
size:string;
imageUrl:string;
constructor(id:number, size:string,
product:Product, qty= 1) {
this.id = id;
this.productId = product.id;
this.price = product.price;
this.size = size;
this.productName = product.name;
this.qty = qty;
this.imageUrl = product.imageUrl;
}
}
This is my car service as you can see I remove and add to cart as well as get cart items, there is no problem here. The remove and add are button clicks on html
export class CartService {
product: any;
cartItem: CartItem[] = [];
cartUrl = 'http://localhost:4000/cart';
constructor(private http: HttpClient, private router: Router,
private route: ActivatedRoute) {
}
getCartItems(): Observable<CartItem[]> {
return this.http.get<CartItem[]>(cartUrl).pipe(
map((result: any[]) => {
let cartItems: CartItem[] =[];
for(let item of result) {
cartItems.push( new CartItem(item.id, item.size,
item.product, item.imageUrl ));
}
return cartItems;
})
);
}
addProductToCart(product:Product):Observable<any>{
return this.http.post(cartUrl, {product});
}
RemoveProductFromCart(id:number):Observable<void>{
//this.cartItems.splice(index,1)
alert("show deleted item");
return this.http.delete<CartItem[]>(`${this.cartUrl}/${id}`)
.pipe(catchError(_err => of (null))
);
}
buttonClick() {
const currentUrl = this.router.url;
this.router.navigateByUrl('/', {skipLocationChange:
true}).then(() => {
this.router.navigate([currentUrl]);
});
//alert("Should Reload");
}
addPurseToCart(product:Product):Observable<any>{
return this.http.post(cartUrl, {product})
}
}
Here is the checkout component, I injected the cart component so I could call the the empty cart function which resides in the cart component. I did import the CartComponent. Check out is based on cart. When the cart is emptied so should checkout
#Component({
providers:[CartComponent], //injected CartComponent
selector: 'app-checkout',
templateUrl: './checkout.component.html',
styleUrls: ['./checkout.component.scss']
})
export class CheckoutComponent implements OnInit {
// #ViewChild(CartComponent) // #ViewChild(CartItemComponent) cartitemComponent: CartItemComponent
cartComponent: CartComponent
#Input() product: CartItem;
#Input() cartItem: CartItem;
cartUrl = 'http://localhost:4000/cart';
size;
cartItems = [];
cartTotal = 0;
itemTotal = 0;
shipping = 8.00;
estimatedTax = 0;
myValue: any;
constructor(private msg: MessengerService, private route:
ActivatedRoute,
private router: Router, private
cartService:CartService,
private productService: ProductService, private
comp:CartComponent) {}
ngOnInit() {
this.loadCartItems();
}
}
loadCartItems(){
this.cartService.getCartItems().subscribe((items:
CartItem[]) => {
this.cartItems = items;
this.calcCartTotal();
this.calNumberOfItems();
})
}
calcCartTotal() {
this.cartTotal = 0;
this.cartItems.forEach(item => {
this.cartTotal += (item.qty * item.price);
})
this.cartTotal += this.shipping;
this.myValue = this.cartTotal
render(
{
id:"#paypal-button-container",
currency: "USD",
value: this.myValue,
onApprove: (details) =>{
alert("Transaction Suceessfull")
console.log(this.myValue);
this.comp.handleEmptyCart();
}
}
);
}
calNumberOfItems(){
console.log("Trying to get tolal items")
this.itemTotal = 0;
this.cartItems.forEach(item => {
this.itemTotal += item.qty;
})
}
}
cart component
export class CartComponent implements OnInit {
#Input() product: CartItem;
#Input() cartItem: CartItem;
//items: CartItem [] =[];
cartUrl = 'http://localhost:4000/cart';
val;
size;
cartItems = [];
cartTotal = 0
itemTotal = 0
constructor(private msg: MessengerService, private
cartService:CartService, private productService:
ProductService, private formBuilder:FormBuilder, private
_data:AppserviceService, private router:Router) { }
ngOnInit(): void {
this.handleSubscription();
this.loadCartItems();
}
handleSubscription(){
this.msg.getMsg().subscribe((product: Product) => {
})
}
loadCartItems(){
this.cartService.getCartItems().subscribe((items:
CartItem[]) => {
this.cartItems = items;
console.log("what is in cartItems" + this.cartItems)
console.log("What does this property hold" +
this.cartItem)
this.calcCartTotal();
this.calNumberOfItems();
})
}
calcCartTotal() {
this.cartTotal = 0
this.cartItems.forEach(item => {
this.cartTotal += (item.qty * item.price)
})
}
calNumberOfItems(){
console.log("Trying to get tolal items")
this.itemTotal = 0
this.cartItems.forEach(item => {
this.itemTotal += item.qty
})
}
handleEmptyCart(){
alert("Hit Empty Cart");
/*here I get the cart items to see what is in the array
and try to empty, it does show tow objects in the
array*/
this.cartService.getCartItems().subscribe((items:
CartItem[]) => {
this.cartItems = items;
this.cartItems.length=0
// this.cartItems = [];
console.log("what is in cartItems" + this.cartItems)
})
}
}
I have used different approaches trying to empty the cart nothing works. It makes me think I'm stepping on something or somehow creating events calling the loadCartItems to many times not sure but according to my research one of these approaches should work. If someone can please help me out I'm stuck. I would greatly appreciate it.
Short answer: run change detection ChangeDetectorRef.detectChanges()
Long answer:
You need to understand how angular works.
Lets assume simple example:
<div id="val">{{val}}</div><button (click)="val++">Increase<div>
So when u click button variable changes, but who changes actual #val div content? Answer is that Angular uses zone.js to patch/change a lot of functions to run Angular change detection after most of JS events (you can control type of this events to include/exclude some of them). Also Promise is patched same way, thats why after some Promise is resolve change detection is run.
However, here you run some render method with onApprove callback which is probably some 3rd party library (?) and zone.js is not aware of it (https://angular.io/guide/zone#ngzone-run-and-runoutsideofangular). And though running detectChanges gonna help u, u better re-write your code, so onApprove is always in Angular zone and u never gonna face similar bugs in future when using this method.

How to update subscribed value in html on change in Angular?

After clicking "Edit", "editStatus" function is called, then the value of "order.status" is changing. But the html view remains the same - displays the old status of order. It changes only after refreshing the page. How can I do the status show the updated variable after change?
html:
<div *ngIf="order">
<p>Id:<b> {{ order._id }}</b></p>
<p>Status:<b> {{ order.status }}</b></p>
</div>
<button (click)="editStatus(order)">Edit</button>
ts file:
private subscribe: Subscription;
order: Order;
constructor(private orderService: OrderService, private route: ActivatedRoute, public router: Router) { }
ngOnInit() {
this.subscribe = this.route.params.pipe(
map(({ id }) => id),
switchMap((id: string) => this.orderService.getOrderById(id)))
.subscribe((res) => {
this.order = res;
});
}
ngOnDestroy() {
this.subscribe.unsubscribe();
}
editStatus(order) {
const orderEdited = { order, status: 'order_canceled' };
this.orderService.editStatus(orderEdited).subscribe(
res => {
console.log(res);
},
err => console.log(err)
);
}
order service:
private userOrdersUrl = 'http://localhost:3000/api/auth/user-orders';
getOrderById(orderId): Observable<Order> {
return this.http.get<Order>(`${this.userOrdersUrl}/${orderId}`);
}
editStatus(order) {
return this.http.put<Order>(this.userOrdersUrl, order);
}
Looks like a student homework...
You do not assign the updated order to your variable. Change to the following:
res => {
this.order = res;
},

JSON data not displaying in Ionic HTML file

I have got my data from my API and it is logged in the console. However, I am unable to access it through my HTML file. I'm not sure why it isn't working? (Looked at other questions and still no joy).
ts file
patients: [];
constructor(private viewService: ViewPatientService ) { }
ngOnInit() {
this.viewService.viewPatient().subscribe(data => {
console.log(data);
});
html file
<ion-item *ngFor="let patient of patients">
Name: {{patient.patients.data[0].FirstName}}
</ion-item>
Please note data should hold the patients array, if not add the property as needed.
patients: [];
constructor(private viewService: ViewPatientService) { }
ngOnInit() {
this.viewService.viewPatient().subscribe(data => {
console.log(data);
this.patients = data
});
}
You haven't assigned the value to patients array
patients: [];
constructor(private viewService: ViewPatientService ) { }
ngOnInit() {
this.viewService.viewPatient().subscribe(data => {
**this.patients = data;**
console.log(data);
});
patients: any;
constructor(private viewService: ViewPatientService ) { }
ngOnInit() {
this.viewService.viewPatient().subscribe(data => {
this.patients = [data];
console.log(data);
});

Print JSON response from REST api in ionic

I'm trying to print a JSON response that I get from a RESTful API request like that:
products:Observable<any>;
constructor(public navCtrl: NavController, private backgroundGeolocation: BackgroundGeolocation, public zone: NgZone, private auth: AuthService, public httpClient: HttpClient)
{
this.products = this.httpClient.get('http://127.0.0.1:8000/product');
}
It works fine, indeed if I print result in console:
this.products
.subscribe(data => {
console.log('my data: ', data);
});
the data is right.
But now, I don't know how to print them out onto a HTML page. I've tried this but it doesn't work:
<ion-list>
<ion-item *ngFor="let p of (products | async)?.results">{{ p.productName}}
</ion-item>
</ion-list>
Are there other ways to resolve the problem?
My JSON response is like that:
0: Object { idProduct: "1", productName: "Pasta", purchased: "0" }
​
1: Object { idProduct: "2", productName: "latte", purchased: "0" }
I have resolved the trouble. I want to post the solution to help other users in this bad situation.
Solution is so simple. I created a new typescript file called: 'rest-service' made up by:
#Injectable()
export class RestServiceProvider {
constructor(public http: HttpClient) {
console.log('Hello RestServiceProvider Provider');
}
getUsers() {
return new Promise(resolve => {
this.http.get('http://127.0.0.1:8000/product').subscribe(data => {
resolve(data);
}, err => {
console.log(err);
});
});
}
}
Now, in home.ts I've done that:
getUsers() {
this.restProvider.getUsers()
.then(data => {
this.products = data;
console.log(this.products);
});
}
And then, in the constructor, that:
this.getUsers();
In HTML side instead, the solution is very very simple:
<ion-item *ngFor="let p of products"> {{ p.productName }}
However, thanks to all
please try to convert products to array object. That may fix your problem.
this.products = this.products.json();
UPDATE
Looks like you found the solution. Normally I don't prefer doing *ngFor directly at a function
<!-- DON'T DO THIS -->
<ion-item *ngFor="let item of someFunction()">
but rather define a variable above the constructor, and then assign data. A separate file wouldn't be necessary, but can be useful if you are doing the same request over and over.
TypeScript
items: Array<any> = [];
constructor() {
// ...
}
ionViewDidLoad() {
this.http.get('https://someurl.com/data').subscribe((data: any) => {
this.items = data;
}).catch(err => console.error('Something went wrong: ', err));
}
HTML
<ion-item *ngFor="let item of items">
{{ item.name }}
</ion-item>
Old answer
What happens if you just do following?
<ion-item *ngFor="let p of products">
Any reason why you are trying to access .results on the products-array?
If you get any errors in the console, please share them with us.

TypeError: Cannot read property 'map' of undefined with Angular v6

For some reason the response JSON is not mapping correctly
Here is my html.
profile-search.component.html
<h3>Enter Username</h3>
<input (keyup)="search($event.target.value)" id="name" placeholder="Search"/>
<ul>
<li *ngFor="let package of packages$ | async">
<b>{{package.name}} v.{{package.repos}}</b> -
<i>{{package.stars}}</i>`enter code here`
</li>
</ul>
Here is component that the html pulls from.
profile-search.component.ts
import { Component, OnInit } from '#angular/core';
import { Observable, Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';
import { NpmPackageInfo, PackageSearchService } from './profile-search.service';
#Component({
selector: 'app-package-search',
templateUrl: './profile-search.component.html',
providers: [ PackageSearchService ]
})
export class PackageSearchComponent implements OnInit {
withRefresh = false;
packages$: Observable<NpmPackageInfo[]>;
private searchText$ = new Subject<string>();
search(packageName: string) {
this.searchText$.next(packageName);
}
ngOnInit() {
this.packages$ = this.searchText$.pipe(
debounceTime(500),
distinctUntilChanged(),
switchMap(packageName =>
this.searchService.search(packageName, this.withRefresh))
);
}
constructor(private searchService: PackageSearchService) { }
toggleRefresh() { this.withRefresh = ! this.withRefresh; }
}
Service that component pulls from.
profile-search.service.ts
import { Injectable, Input } from '#angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '#angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { HttpErrorHandler, HandleError } from '../http-error-handler.service';
export interface NpmPackageInfo {
name: string;
}
export const searchUrl = 'https://api.github.com/users';
const httpOptions = {
headers: new HttpHeaders({
'x-refresh': 'true'
})
};
function createHttpOptions(packageName: string, refresh = false) {
// npm package name search api
// e.g., http://npmsearch.com/query?q=dom'
const params = new HttpParams({ fromObject: { q: packageName } });
const headerMap = refresh ? {'x-refresh': 'true'} : {};
const headers = new HttpHeaders(headerMap) ;
return { headers, params };
}
#Injectable()
export class PackageSearchService {
private handleError: HandleError;
constructor(
private http: HttpClient,
httpErrorHandler: HttpErrorHandler) {
this.handleError = httpErrorHandler.createHandleError('HeroesService');
}
search (packageName: string, refresh = false): Observable<NpmPackageInfo[]> {
// clear if no pkg name
if (!packageName.trim()) { return of([]); }
// const options = createHttpOptions(packageName, refresh);
// TODO: Add error handling
return this.http.get(`${searchUrl}/${packageName}`).pipe(
map((data: any) => {
return data.results.map(entry => ({
name: entry.any[0],
} as NpmPackageInfo )
)
}),
catchError(this.handleError('search', []))
);
}
}
I have tried to alter
return this.http.get(`${searchUrl}/${packageName}`).pipe(
map((data: any) => {
return data.results.map(entry => ({
name: entry.any[0],
} as NpmPackageInfo )
)
to
login: data.login, and login: entry.login but keep getting the below error.
http-error-handler.service.ts:33 TypeError: Cannot read property 'map'
of undefined
at MapSubscriber.project (profile-search.service.ts:49)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next
(map.js:75)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next
(Subscriber.js:93)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next
(map.js:81)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next
(Subscriber.js:93)
at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/operators/filter.js.FilterSubscriber._next
(filter.js:85)
at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next
(Subscriber.js:93)
at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber.notifyNext
(mergeMap.js:136)
at InnerSubscriber.push../node_modules/rxjs/_esm5/internal/InnerSubscriber.js.InnerSubscriber._next
(InnerSubscriber.js:20)
at InnerSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next
(Subscriber.js:93)
results in data.results is probably undefined, check that the data object matches the schema you're expecting it to.
map working on array but this.http.get(${searchUrl}/${packageName}) return object not array.
so data.results is undefined.
This is how I converted my object into an array, if anyone has a better way of doing please let me know.
return this.http.get(`${searchUrl}/${packageName}`).pipe(
map((data: any) => {
console.log(data);
var profile = Object.keys(data).map(function(key) {
return [(key) + ': ' + data[key]];
}
);
console.log(profile);
data = profile;
return data;
}),
catchError(this.handleError<Error>('search', new Error('OOPS')))
);
}
}
I fixed this issue by eliminating ".results"
from
.map((data: any) => this.convertData(data.results))
to
.map((data: any) => this.convertData(data))
To avoid the error, change
map((items) => items.map
to
map((items) => items?.map
Then set your result set as an empty array:
this.list = data ?? [];
PS: Used with Angular 14. In older versions you may need to change last one to data ? data : []