Empty response when trying to fetch mock data from Service - javascript

I want to fetch and display data from Array of Objects.
I have created the parameterized routes.
1. app-routing.module.ts
const routes: Routes = [
{
path: 'all-trades',
component: AllTradesComponent,
},
{
path: 'crop/:name', component: CropComponent
}]
2. Crop.ts
export class Crop {
name: string;
checked: boolean;
subCategory: Subcategory[];
}
export class Subcategory {
id: number;
name: string;
isActive: boolean;
}
3. CropData.ts
Here is my Array of object, I want to access subCategory and display the name on webpage.
for example: When user click on Rice then its should get the result like 'Basmati', 'Ammamore'
OR
When user click on Wheat then its should get the result like 'Durum', 'Emmer'
OR
When user click on Barley then its should get the result like 'Hulless Barley', 'Barley Flakes'
import { Crop } from './Crop';
export const CROP: Crop[] = [
{
name: 'Rice',
checked: true,
subCategory: [
{
id: 1,
name: 'Basmati',
isActive: true,
},
{
id: 2,
name: 'Ammamore',
isActive: true,
},
],
},
{
name: 'Wheat',
checked: true,
subCategory: [
{
id: 1,
name: 'Durum',
isActive: true,
},
{
id: 2,
name: 'Emmer',
isActive: true,
},
],
}, {
name: 'Barley',
checked: true,
subCategory: [
{
id: 1,
name: 'Hulless Barley',
isActive: true,
},
{
id: 2,
name: 'Barley Flakes',
isActive: true,
},
],
}
]
4.1 crop.service.ts
// First I tried this logic
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs';
import { skipWhile } from 'rxjs/operators';
import { Crop } from '../shared/Crop';
import { CROP } from '../shared/cropdata';
#Injectable({
providedIn: 'root'
})
export class CropService {
constructor() { }
CropData: Crop
getCrop(name: string): Crop {
return this.CropData.filter((crop) => (crop.name === name))[0];
}
}
4.2 crop.service.ts
// Then I tried this logic
export class CropService {
private selectedCrop= new BehaviorSubject<Crop>(null);
setCrop(crop:Crop){
this.selectedCrop.next(crop);
}
getCrop(){
this.selectedCrop.asObservable().pipe(skipWhile(val=> val === null));
}
}
I failed in both the cases.
5.1 all-trades.components.ts
// First tried using function
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute, Router } from '#angular/router';
import { Crop } from 'src/app/shared/Crop';
import { CropService } from '../crop.service';
#Component({
selector: 'app-all-trades',
templateUrl: './all-trades.component.html',
styleUrls: ['./all-trades.component.css'],
})
export class AllTradesComponent implements OnInit {
constructor(private service: CropService, private router: Router) { }
// Here I tried to make use of function but still its doesnot giving me the desire result
onSelect(selectedCrop:Crop){
this.service.setCrop(selectedCrop);
this.router.navigateByUrl(`crop/${crop.name}`);
}
onChange(event, index, item) {
item.checked = !item.checked;
console.log(index, event, item);
}
ngOnInit(): void { }
}
5.1 all-trades-component.html
<app-header></app-header>
<div
fxLayout="row"
fxLayout.lt-md="column"
fxLayoutAlign="space-between start"
fxLayoutAlign.lt-md="start stretch"
>
<div class="container-outer" fxFlex="20">
<div class="filters">
<section class="example-section">
<span class="example-list-section">
<h1>Select Crop</h1>
</span>
<span class="example-list-section">
<ul>
<li *ngFor="let crop of crops">
<mat-checkbox
[checked]="crop.checked"
(change)="onChange($event, i, crop)"
>
{{ crop.name }}
</mat-checkbox>
</li>
</ul>
</span>
</section>
<div class="content container-outer" fxFlex="80">
<mat-card
class="crop-card"
style="min-width: 17%"
*ngFor="let crop of crops"
[hidden]="!crop.checked"
>
<!-- here i call the function -->
<a (click)="onSelect(crop)" routerLinkActive="router-link-active">
<mat-card-header>
<img
mat-card-avatar
class="example-header-image"
src="/assets/icons/crops/{{ crop.name }}.PNG"
alt="crop-image"
/>
<mat-card-title>{{ crop.name }}</mat-card-title>
<mat-card-subtitle>100 Kgs</mat-card-subtitle>
</mat-card-header>
</a>
<mat-card-content>
<p>PRICE</p>
</mat-card-content>
</mat-card>
</div>
</div>
<app-footer></app-footer>
crop-componet.ts
import { Component, OnInit } from '#angular/core';
import { Subscription } from 'rxjs';
import { Crop } from 'src/app/shared/Crop';
#Component({
selector: 'app-crop',
templateUrl: './crop.component.html',
styleUrls: ['./crop.component.css']
})
export class CropComponent implements OnInit {
service: any;
crop: any;
route: any;
cropservice: any;
sub: Subscription;
constructor() { }
ngOnInit(): void {
// let name = this.route.snapshot.params['name'];
// this.crop = this.cropservice.getCrop(name);
this.sub = this.route.paramMap.subscribe(params => {
let name = params.get("name")
this.crop = this.cropservice.getCrop(name)
})
}
}
7. crop-component.html
<div *ngFor="let category of crop.subCategory">{{category.id}}</div>
This is my eniter code I dont know where I am going wrong please help in fetching data from arrays of object.
[![enter image description here][1]][1]
This is my all-trades.component.html output
When I click Rice I get this as output (Url get change )
[![enter image description here][2]][2]
When I click Wheat I get this
[![enter image description here][3]][3]
And so on....
I just want to display the name of subCategory Array.
Please give me the solution.
[1]: https://i.stack.imgur.com/kxdyj.png
[2]: https://i.stack.imgur.com/OOAtc.png
[3]: https://i.stack.imgur.com/PVcfT.png

On your 4.1 you seem to forget to assign your mock data into your variable
....
import { CROP } from '../shared/cropdata';
#Injectable({
providedIn: 'root'
})
export class CropService {
constructor() { }
CropData: Crop[] = CROP; // Assign the value
getCrop(name: string): Crop {
return this.CropData.filter((crop) => (crop.name === name))[0];
}
}
On your 4.2, you forgot to assign your mock data as well in your BehaviorSubject if you end up using this method. BehaviorSubjects are known to emit initial data
...
import { CROP } from '../shared/cropdata';
export class CropService {
private selectedCrop = new BehaviorSubject<Crop[]>(CROP); // Pass CROP mock data
setCrop(crop: Crop[]) {
this.selectedCrop.next(crop);
}
getCrop() {
this.selectedCrop.asObservable().pipe(skipWhile(val=> val === null));
}
}
Have created a Stackblitz Demo for your reference. You can check the console for the response

Related

new BehaviorSubject returning Null Id

i'am in the process of creating a shoping cart but i have this weird probleme were the Id of the basket always null
basket.ts
import { v4 as uuidv4 } from 'uuid';
export interface IBasket {
id: string;
items: IBasketItem[];
}
export interface IBasketItem {
id: number;
productName: string;
price: number;
quantity: number;
pictureUrl: string;
brand: string;
type: string;
}
export class Basket implements IBasket {
id: string = uuidv4();
items: IBasketItem[] = [];
}
basket service
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { BehaviorSubject, map } from 'rxjs';
import { environment } from 'src/environments/environment';
import { Basket, IBasket, IBasketItem } from '../shared/Models/basket';
import { IProduct } from '../shared/Models/product';
#Injectable({
providedIn: 'root',
})
export class BasketService {
baseUrl = environment.apiUrl;
private basketSource = new BehaviorSubject<IBasket>(null);
basket$ = this.basketSource.asObservable();
constructor(private http: HttpClient) {}
getBasket(id: string) {
return this.http.get<IBasket>(this.baseUrl + 'basket?id=' + id).pipe(
map((basket: IBasket) => {
this.basketSource.next(basket);
})
);
}
setBasket(basket: IBasket) {
return this.http.post<IBasket>(this.baseUrl + 'basket', basket).subscribe(
(response: IBasket) => this.basketSource.next(response),
(error) => {
console.log(error);
}
);
}
getCurrentBasketValue() {
return this.basketSource.getValue();
}
addItemToBasket(item: IProduct, quantity = 1) {
const itemToAdd: IBasketItem = this.mapProductItemToBasketItem(
item,
quantity
);
const basket = this.getCurrentBasketValue() ?? this.createBasket();
basket.items = this.addOrUpdateItem(basket.items, itemToAdd, quantity);
console.log(basket);
// this.setBasket(basket);
}
private addOrUpdateItem(
items: IBasketItem[],
itemToAdd: IBasketItem,
quantity: number
): IBasketItem[] {
const index = items.findIndex((i) => i.id === itemToAdd.id);
if (index === -1) {
itemToAdd.quantity = quantity;
items.push(itemToAdd);
} else {
items[index].quantity += quantity;
}
return items;
}
private createBasket(): IBasket {
const basket = new Basket();
console.log('ezeze');
localStorage.setItem('basket_id', basket.id);
return basket;
}
private mapProductItemToBasketItem(
item: IProduct,
quantity: number
): IBasketItem {
return {
id: item.id,
productName: item.name,
price: item.price,
pictureUrl: item.pictureUrl,
quantity,
brand: item.productBrand,
type: item.productType,
};
}
}
product-item.ts
import { Component, OnInit, Input } from '#angular/core';
import { BasketService } from 'src/app/basket/basket.service';
import { IProduct } from 'src/app/shared/Models/product';
#Component({
selector: 'app-product-item',
templateUrl: './product-item.component.html',
styleUrls: ['./product-item.component.scss'],
})
export class ProductItemComponent implements OnInit {
#Input() product: IProduct;
constructor(private basketService: BasketService) {}
ngOnInit(): void {}
addItemToBasket() {
this.basketService.addItemToBasket(this.product);
}
}
product-item.html
<div class="card h-100 shadow-sm">
<div class="image position-relative" style="cursor: pointer">
<img
src="{{ product.pictureUrl }}"
alt="{{ product.name }}"
srcset=""
class="img-fluid bg-light"
/>
<div class="d-flex align-items-center justify-content-center hover-overlay">
<button
(click)="addItemToBasket()"
type="button"
class="btn btn-secondary fa fa-shopping-cart me-2"
></button>
<button
routerLink="/shop/{{ product.id }}"
type="button"
class="btn btn-secondary"
>
view
</button>
</div>
</div>
<div class="card-body d-flex flex-column">
<a routerLink="/shop/{{ product.id }}">
<h6 class="text-uppercase">{{ product.name }}</h6>
</a>
<span class="mb-2">{{ product.price | currency }}</span>
</div>
</div>
so basically the problem appears when i click on a product the id of of the basket is always null
the items are adding up but the Id is null
ex:{
"id": "null",
"items": [
{
"id": 8788,
"productName": "T Blues",
"price": 20,
"pictureUrl": "*********/images/products/bo.png",
"quantity": 1,
"brand": "Y",
"type": "Z"
}
]
}
any idea how to solve this ?
The BehaviorSubject returns the last item sent to it.
you are initializing it with a null:
(...)
export class BasketService {
baseUrl = environment.apiUrl;
// \/ here
private basketSource = new BehaviorSubject<IBasket>(null);
so the first time you subscribe to its value, it will yield null
I don't see a call to getBasket on your component, it might not have been called... or the service might not have responded in time to provide the next value into basketSource
also BehaviorSubject's are better used as Observables, to avoid issues with its value.
you should remove the function
getCurrentBasketValue() {
return this.basketSource.getValue();
}
make the prop basketSource public and get its value filtering out nulls when needed as the following:
basketService.basketSource.pipe(filter(x=>x), take(1)).subscribe(source => {
// your code here,
})

Dynamically URL navigation between mattabs

I have an application which looks like on the image below.I used mattabs inside nav links.
this.navLinks = [
{
label: 'Preview',
link: './1',
index: 0
}, {
label: 'Tuning',
link: './tabtest2',
index: 1
}, {
label: 'Payment',
link: './tabtest3',
index: 2
},
];
in this code part when I press preview it shows me the 2nd element on the list(array).Thats exactly how I want it to work but it should be controlled dynamically.I made string concatanation and changed with that link on the preview tab but URL isnt recognizable.My concatanation is exactly same like '.1' on the link property
Here's what I tried below
TS File
import { Component, OnInit } from '#angular/core';
import { Car } from './car.model';
import { CarService } from './car.sevice';
import { Router, ActivatedRoute, Params } from '#angular/router';
import { Subject } from 'rxjs';
#Component({
selector: 'app-cars',
templateUrl: './cars.component.html',
styleUrls: ['./cars.component.css']
})
export class CarsComponent implements OnInit {
navLinks: any[];
public href: string = "";
activeLinkIndex = -1;
mySubject;
ngOnInit(): void {
this.href = this.router.url;
console.log(this.router.url);
this.router.events.subscribe((res) => {
this.activeLinkIndex = this.navLinks.indexOf(this.navLinks.find(tab => tab.link === '.' + this.router.url));
});
this.mySubject=this.carService.carrierSubject.subscribe(value=>
{
this.id=value;
let numid=this.id.toString();
this.newString="./".concat(numid);
console.log(this.newString);
})
}
newString:string='';
id:number;
car:Car;
constructor(private carService:CarService,private route: ActivatedRoute,private router: Router) {
this.navLinks = [
{
label: 'Preview',
link: '.1',
index: 0
}, {
label: 'Tuning',
link: './tabtest2',
index: 1
}, {
label: 'Payment',
link: './tabtest3',
index: 2
},
];
}
onTuning()
{
this.router.navigate(['tuning'], {relativeTo: this.route});
}
}
HTML
<div class="row">
<div class="col-md-5">
<app-car-list></app-car-list>
</div>
<div class="col-md-7">
<nav mat-tab-nav-bar>
<a mat-tab-link
*ngFor="let link of navLinks"
[routerLink]="link.link"
routerLinkActive #rla="routerLinkActive"
[active]="rla.isActive">
{{link.label}}
</a>
</nav>
<router-outlet></router-outlet>
</div>
</div>

How to map and bind Dropdown items in Angular 6?

i have a dropdown which has option like testOptions.
i get data from service for these option to Map like 'Y' for Yes , 'N' for 'No' and 'U' for unconfirmed in property optionTest .
import { Component, OnInit, createPlatformFactory } from '#angular/core';
#Component({
selector: 'app-test-information',
templateUrl: './app-test-information.component.html',
styleUrls: ['./app-test-information.component.scss']
})
export class TestInfoComponent implements OnInit {
Id :Items;
public testOptions: Items[] = [
{
id: 1,
name: 'NA',
},
{
id: 2,
name: 'Yes',
},
{
id: 3,
name: 'No',
},
{
id: 4,
name: 'Unconfirmed'
}
];
ngOnInit() {
this.infoService.getData()
.subscribe((result :InfoResults ) => this.data = result
, undefined,
() => {
if (this.data) {
this.readOnlyData()
}
})
readOnlyData() {
//here i am trying to find item in testOptions and bind the data from service
this.Id=this.testOptions.find((item) => item.name === "Yes" ) ;
}
}
<!-- Model class for items : -->
export class Items {
public id ?: number;
public name : string;
}
export class InfoResults {
public optionTest : string;
}
how we can map or get this.id if options from service are coming in data like 'Y' for Yes , 'N' for 'No' and 'U' for unconfirmed?
Please help.
Thanks!

Processing a two-dimensional array in Angular 7. ngFor

How to handle a two-dimensional array using ngFor?
I receive here such array
As a result, I need to get the blocks in which the data from the array is displayed in order. That is, in the case of an array that is represented on the screen, there would be 10 blocks.
Example:
<div>
<span>Yandex</span>
<span>Yandex.N.V....</span>
<span>https://en.wikipedia.org/wiki/Yandex</span>
</div>
<div>
<span>Yandex Browser</span>
<span>IPA:...</span>
<span>https://en.wikipedia.org/wiki/Yandex_Browser</span>
</div>
etc.
I do it that way.
<h3>Get Articles</h3>
<div>
<div *ngIf="articles">
<div *ngFor="let article of articles">
<span>{{ article[1] }}</span>
<span>{{ article[2] }}</span>
<span>{{ article[3] }}</span>
</div>
</div>
</div>
I understand that this is wrong, but I can not find my stupid mistake.
The output is either an error or a strange conclusion.
search.component.ts
import { Component, OnInit } from '#angular/core';
import { Article, ArticlesService } from '../../services/articles.service';
#Component({
selector: 'app-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.css'],
providers: [ArticlesService]
})
export class SearchComponent implements OnInit {
constructor(private articlesServices: ArticlesService) { }
searchQuery: string;
limit: number;
error: any;
articles: { };
// noinspection JSMethodCanBeStatic
getUrl(searchQuery: string) {
return 'https://en.wikipedia.org/w/api.php?action=opensearch&search='
+ searchQuery + '&limit=10&namespace=0&format=json&origin=*';
}
showArticles() {
this.articlesServices.getArticles(this.getUrl(this.searchQuery))
.subscribe(
(data: Article) => this.articles = Object.values({
title: data[0],
collection: data[1],
description: data[2],
links: data[3]
}),
error => this.error = error
);
console.log(this.articles);
}
ngOnInit() {
}
}
article.component.ts
import { Component, OnInit, Input } from '#angular/core';
import {Article, ArticleInfo, ArticlesService} from '../../services/articles.service';
#Component({
selector: 'app-articles',
templateUrl: './articles.component.html',
styleUrls: ['./articles.component.css'],
})
export class ArticlesComponent implements OnInit {
#Input() articles: Article;
#Input() searchQuery: string;
constructor(private articlesServices: ArticlesService) { }
information: ArticleInfo;
getUrl(searchQuery: string) {
return 'https://ru.wikipedia.org/w/api.php?action=query&list=search&srsearch=' +
searchQuery + '&utf8=&format=json&origin=*';
}
showArticlesInformation() {
this.articlesServices.getArticlesInfo(this.getUrl(this.searchQuery))
.subscribe(
(data: ArticleInfo) => this.information = {
query: data.query.search
}
);
console.log(this.information);
}
ngOnInit() {
}
}
article.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpErrorResponse } from '#angular/common/http';
import { throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
export interface Article {
title: string;
collection: string[];
description: string[];
links: string[];
}
export interface ArticleInfo {
query: {
search
};
}
#Injectable({
providedIn: 'root'
})
export class ArticlesService {
constructor(private http: HttpClient) { }
getArticles(url) {
return this.http.get(url)
.pipe(
retry(3),
catchError(this.handleError)
);
}
getArticlesInfo(url) {
return this.http.get<ArticleInfo>(url);
}
// noinspection JSMethodCanBeStatic
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
console.error('An error occurred:', error.error.message);
} else {
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${error.error}`);
}
return throwError(
'Something bad happened; please try again later.');
}
}
Come 2D array
Then it should turn out like this
Try this,
<div>
{{articles[0]}}
</div>
<div *ngFor="let article of articles[1]; let i=index">
<span>
{{article}}
</span>
<span *ngFor="let info1 of articles[2]; let j=index" [hidden]="i!=j">
{{info1}}
</span>
<span *ngFor="let info2 of articles[3]; let k=index" [hidden]="i!=k">
{{info2}}
</span>
</div>
Try storing the result into Observable and into the html file use async pipe.
<div *ngFor="let article of articles | async">
In your search.component.ts
articles : Observable<Article>;
...
this.articles = this.articlesServices.getArticles(this.getUrl(this.searchQuery)).catch(error => this.error = error );

getData from multiple filters does not return anything

I can't get my getData function on app.component.ts to return the query with all the arguments for the API Request. I don't get any errors and I also can't console.log inside the function because it doesn't work. It skips everything I write inside getData. Any ideas?
app.component.ts
#Component({
/**
* Tag to show component in html
*/
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [MedicineService]
})
export class AppComponent implements OnInit, AfterViewInit {
#ViewChildren(FiltersComponent) filters: QueryList<FiltersComponent>;
title = 'Base Remédios';
_medicines: Medicine[];
resourceType: Filter[] = [
{
id: 'all',
title: 'All',
active: true,
},
{
id: 'texto1',
title: 'Texto1',
},
{
id: 'texto2',
title: 'Texto2',
},
{
id: 'texto3',
title: 'Texto3',
},
];
levels: Filter[] = [
{
id: 'grupo1',
title: 'Grupo1',
active: true,
},
{
id: 'grupo2',
title: 'Grupo2',
},
{
id: 'grupo3',
title: 'Grupo3',
},
];
private resources: Observable<any>;
constructor(private _medicineService: MedicineService) {
}
/**
* Function to get array itens of endpoints
*/
getMedicines(): void {
this._medicineService.getMedicines()
.subscribe(
resultArray => this._medicines = resultArray,
error => console.log(error));
}
ngOnInit(): void {
this.getMedicines();
}
ngAfterViewInit() {
const filters = this.filters.map(f => f.changeFilter);
console.log('oi');
this.resources = combineLatest(...filters).pipe(
map((filters: ActiveFilter[]) =>
filters.map(filter => `${filter.group}=${filter.id}`).join('&')),
switchMap(this.getData));
}
getData(query) {
return timer(1).mapTo('https://api.com?' + query);
}
}
filter.component.ts
export interface ActiveFilter {
id: number | string;
group: string;
}
export interface Filter {
id: string | string;
title: string;
active?: boolean;
}
#Component({
selector: 'app-filters',
templateUrl: './filters.component.html',
styleUrls: ['./filters.component.css']
})
export class FiltersComponent implements OnInit, OnDestroy {
#Input() group: string;
#Input() filters: Filter[] = [];
changeFilter;
ngOnInit(): void {
const initialFilter = this.filters.find(f => f.active);
this.changeFilter = new BehaviorSubject<ActiveFilter>({
group: this.group,
id: initialFilter.id
});
}
ngOnDestroy() {
this.changeFilter.unsubscribe();
}
select(filter: Filter) {
console.log('click funciona');
this.filters.forEach(filter => filter.active = false);
filter.active = true;
this.changeFilter.next({
group: this.group,
id: filter.id
});
}
}
filters.component.html
<ul>
<li *ngFor="let filter of filters" (click)="select(filter)" [ngClass]="{ active: filter.active }">
{{filter.title}}
</li>
</ul>
app.component.html
<section>
<app-filters [filters]="resourceType" group="type"></app-filters>
<app-filters [filters]="levels" group="level"></app-filters>
</section>
There is issue with the parameter you are passing to switchMap function of rxjs.
Modified code -
ngAfterViewInit() {
const filters = this.filters.map(f => f.changeFilter);
console.log('oi');
this.resources = combineLatest(...filters).pipe(
map((filters: ActiveFilter[]) =>
filters.map(filter => `${filter.group}=${filter.id}`).join('&')),
switchMap(()=>this.getData())); // <------ change here
}
Refer this - https://www.learnrxjs.io/operators/transformation/switchmap.html

Categories