Angular call on JSON arrays - json

I want to output the title of test1 from the first array and the title
of test2 from the second array, any help would be great. Thanks
{
"results": [
{
"id": 21,
"title": "test1",
"identifier": null,
"colour_bg": "#bd2c2c",
"colour_btn": "#a11212",
"colour_content_bg": "#ffffff",
"logo_dashboard": "collection/21/SVwnz6tjluX81dIRNXjZo7issYUWyOVyD3LJFykm.png",
"logo_page": "collection/21/txgkqlkPA45mHSYtqZ5rFa4wLfHNUfXESE0xyhwp.png"
}
],
"links": [
{
"id": 21,
"title": "test2",
"identifier": null,
"colour_bg": "#bd2c2c",
"colour_btn": "#a11212",
"colour_content_bg": "#ffffff",
"logo_dashboard": "collection/21/SVwnz6tjluX81dIRNXjZo7issYUWyOVyD3LJFykm.png",
"logo_page": "collection/21/txgkqlkPA45mHSYtqZ5rFa4wLfHNUfXESE0xyhwp.png"
}
]
}
My HTML below
<div *ngFor="let result of data">
<h1>{{result.title}}</h1>
</div>

try like this :
stackblitz demo
in ts file :
loadUser() {
this.http.get('assets/json/collection.json')
.map(res => res.json())
.subscribe(data => {
this.data = data;
console.log('this.data', this.data);
})
}
template
<div *ngFor="let result1 of data.results">
<div *ngFor="let result2 of data.links">
<h1>{{result1.title}}</h1>
<h1>{{result2.title}}</h1>
</div>
</div>

<div *ngFor="let result of data; let idx = index">
<h1>{{result.title}}</h1>
<h1>{{links[idx].title}}</h1>
</div>

Related

How to get random object in a json array from server using ngFor Angular

I need to get a random object from a JSON array, now I`m using pipe slice from 0 to 16 in the carousel.
my products are shown one by one, but I want to show them randomly. Can someone help with this???
there is my JSON file:
{
"id": 40,
"name": "car",
"shortDetails": "Cars 2",
"description": "Cars 2",
"pictures": "cars2.png",
"newItem": true,
"category": "PREDEFINED_CAR",
"price": 33,
"sale": false,
"discount": null,
"salePrice": null,
"productType": "CAR",
"sku": "",
"stock": 10,
"subCategory": {
"id": 10,
"name": "Cars",
"translationKey": "Cars",
"relations": null
}
HTML code:
<section class="section-b-space p-t-0">
<div class="container">
<div class="row">
<div class="col">
<owl-carousel-o class="product-m no-arrow" [options]="ProductSliderConfig">
<ng-container *ngFor="let product of products$ | async | slice:0:16">
<ng-template carouselSlide>
<div class="product-box">
<app-product-box
[product]="product"
[currency]="productsService?.Currency"
[thumbnail]="true"
[cartModal]="true">
</app-product-box>
</div>
</ng-template>
</ng-container>
</owl-carousel-o>
</div>
</div>
</div>
</section>
TypeScript code:
constructor(private _store: Store<AppState>) {
this.products$ = this._store.pipe(select(selectProductList));
}
products$;
just shuffle the array of elements. see this SO
produtsSuffle$=this.product$.pipe(
map((res: any[]) =>
res
.map(x => ({ value: x, order: Math.random() }))
.sort((a, b) => a.order - b.order)
.map(x => x.value)
)
);
Update
If we has problems with the suffle always can use a "cache". It's only to have a variable "data". The idea is that you return the suffle array or the data. in the way
//in pseudo code
//return (!data)?the suffle array:of(data)
data:any[]=null;
produtsSuffle$=!data?this.product$.pipe(
map((res: any[]) =>
res
.map(x => ({ value: x, order: Math.random() }))
.sort((a, b) => a.order - b.order)
.map(x => x.value)
),
tap(res=>this.data=res)
):of(data)
Or subscribe to the productSuffle and work with data
produtsSuffle$.subscribe(res=>{
this.data=res;
})
If we has a service "serviceState" we can do
get data(){
return this.serviceState.data;
}
set data(){
this.serviceState.data=data;
}

Cannot use *ngFor for a two-dimensional array in Angular

I saw many similar questions but the solutions there didn't work for me. I want to display orders in Angular.
I receive clients' orders in Json format from Spring. Like this:
[
{
"id": 1,
"orderProducts": [],
"numberOfProducts": 0
},
{
"id": 2,
"orderProducts": [
{
"quantity": 4,
"product": {
"id": 1,
"brand": "apple",
"name": "iphone11",
"categoryId": 1
}
}
],
"numberOfProducts": 1
},
{
"id": 3,
"orderProducts": [
{
"quantity": 9,
"product": {
"id": 1,
"brand": "apple",
"name": "iphone11",
"categoryId": 1
}
},
{
"quantity": 6,
"product": {
"id": 2,
"brand": "xiaomi",
"name": "Note10",
"categoryId": 1
}
},
{
"quantity": 1,
"product": {
"id": 6,
"brand": "cccccccccccccccc",
"name": "cccccccccccccc",
"categoryId": 1
}
}
],
"numberOfProducts": 3
},
{
"id": 4,
"orderProducts": [
{
"quantity": 5,
"product": {
"id": 1,
"brand": "apple",
"name": "iphone11",
"categoryId": 1
}
}
],
"numberOfProducts": 1
}
]
So i created a class in Angular to accept it.
db-orders.ts
export class DbOrders {
id: number;
orders: ProductOrder[];
numberOfProducts: number;
constructor(orders: ProductOrder[]){
this.orders = orders;
}
}
product-order.ts
export class ProductOrder {
product: Product;
quantity: number;
constructor(product: Product, quantity: number){
this.product = product;
this.quantity = quantity;
}
}
product.ts
export class Product {
id: number;
brand: string;
name: string;
category: ProductCategory;
constructor(){}
}
Here is a service class.
order.service.ts
export class OrderService {
private orderUrl: string = 'http://localhost:8080/orders';
constructor(private http: HttpClient) { }
saveOrder(order: ProductOrders) {
console.log("Hello")
return this.http.post<ProductOrders>(this.orderUrl, order);
}
public findOrders(): Observable<DbOrders[]> {
return this.http.get<DbOrders[]>(this.orderUrl);
}
}
order-list.component.ts
export class OrderListComponent implements OnInit {
receivedOrders: DbOrders[] = [];
constructor(private orderService: OrderService) { }
ngOnInit(): void {
this.orderService.findOrders().subscribe(
data =>{
this.receivedOrders = data;
}
);
}
}
order-list.component.html
<div *ngFor="let receivedOrder of receivedOrders">
<p>Number of Products in the order: {{receivedOrder.numberOfProducts}}</p>
<div *ngFor="let order of receivedOrder.orders">
<h1>Product name: {{ order.product.name }}</h1>
</div>
</div>
In this case, only the number of products is displayed,nothing else:
I tried to add a toArray method:
<div *ngFor="let order of toArray(receivedOrder.orders)">
ngOnInit(): void {
this.orderService.findOrders().subscribe(
data =>{
this.receivedOrders = data;
}
);
}
toArray(orders: object) {
return Object.keys(orders).map(key => orders[key])
}
Doesn't work.
Also i tried to add indexes.
<div *ngFor="let receivedOrder of receivedOrders; let i=index"">
<p>Number of Products in the order: {{receivedOrder.numberOfProducts}}</p>
<div *ngFor="let order of receivedOrder.orders; let j=index"">
<h1>Product name: {{ order.product.name }}</h1>
</div>
</div>
Doesn't work either.
What is my mistake? Thank you!
You seem to have a few problems. Firstly, your data structure does not match your classes.
E.g. your ProductOrder object should have an array of OrderProduct objects as that is what your data has.
Your constructor for ProductOrder never gets called because you are no instantiating the object from the class.
In simple terms, change your html to this for it to work:
<div *ngFor="let receivedOrder of data; let i=index">
<p>Number of Products in the order: {{receivedOrder.numberOfProducts}}</p>
<div *ngFor=" let order of receivedOrder.orderProducts; let j=index">
<h1>Product name: {{ order.product.name }}</h1>
</div>
</div>
You can also find a demo on StackBlitz.

Customize mat select dropdown to allow nested values in angular

I'm customizing angular material select/autocomplete to allow nested dropdowns.
Here, I wanted to have one parent dropdown with many childs. If I expand particular parent dropdown, only childs of that dropdown should expand or collapse. Similarly, checkbox event should be selected in the same scenario.
Here, I got [object object] when I select the dropdowns.
console log is provided to give the values selected/unselected.
Can someone help on this?
STACKBLITZ
<mat-form-field appearance="fill">
<mat-label>Toppings</mat-label>
<input type="text" matInput placeholder="Select Users" aria-label="Select Users" matInput [matAutocomplete]="auto" [formControl]="states">
<mat-autocomplete #auto="matAutocomplete">
<mat-select-trigger>
{{states.value ? states.value[0] : ''}}
<span *ngIf="states.value?.length > 1" class="example-additional-selection">
(+{{states.value.length - 1}} {{states.value?.length === 2 ? 'other' : 'others'}})
</span>
</mat-select-trigger>
<mat-optgroup *ngFor="let group of stateList">
<div>
<mat-checkbox [checked]="group.selected" (change)="toggleParent($event, group)" (click)="$event.stopPropagation()">
{{group.letter}}
</mat-checkbox>
<button mat-button (click)="expandDocumentTypes(group)">
<mat-icon>keyboard_arrow_down</mat-icon>
</button>
</div>
<mat-option *ngFor="let name of group.names" [value]="name" [ngClass]="isExpandCategory[group.letter] ? 'list-show' : 'list-hide'">
<mat-checkbox [checked]="group.checked" (change)="toggleSelection($event, name, group)" (click)="$event.stopPropagation()">
{{name}}
</mat-checkbox>
</mat-option>
</mat-optgroup>
</mat-autocomplete>
</mat-form-field>
export class SelectCustomTriggerExample {
constructor(private _formBuilder: FormBuilder) {}
// stateForm: FormGroup = this._formBuilder.group({
// stateGroup: '',
// });
// toppings = new FormControl();
isExpandCategory: boolean[] = [];
toppingList: string[] = ['Extra cheese', 'Mushroom', 'Onion', 'Pepperoni', 'Sausage', 'Tomato'];
stateRecord: any = [];
states = new FormControl();
expandDocumentTypes(group: any) {
console.log("expanding dropdown", group);
this.isExpandCategory[group.letter] = !this.isExpandCategory[group.letter];
// expand only selected parent dropdown category with that childs
}
toggleSelection(event: any, name: any, group: any) {
debugger;
console.log("toggleSelection", name, event.checked, group);
if (event.checked) {
console.log("stastateRecordtelist", this.stateRecord);
this.stateRecord.push(name);
this.states.setValue(this.stateRecord);
console.log("toggleselection ", this.states.value);
} else {
this.stateRecord = this.stateRecord.filter((x: any) => x !== name);
console.log("else toggleselection", name, group, this.states.value);
this.states.setValue(this.states.value.filter((x: any) => x !== name));
console.log("after filter ", this.states.value);
//this.states.setValue([]);
}
}
toggleParent(event: any, group: any) {
debugger;
group.checked = event.checked;
console.log("event", event.checked, "group", group, "states value", this.states.value);
let states = this.states.value;
states = states ? states : [];
if (event.checked) {
states.push(...group.names)
} else {
console.log("else", states);
group.names.forEach((x: string) => {
if (states.indexOf(x) > -1) {
states.splice(states.indexOf(x), 1)
}
});
}
this.states.setValue(states);
console.log("statesvalue", this.states.value);
if (!event.checked) {
this.states.setValue(this.states.value.filter((x: any) => !x.includes(group.names)))
//this.states.setValue([]);
}
console.log("final statesvalue", this.states.value);
}
stateList = [{
"letter": "A",
"checked": false,
"names": [{
"id": 1,
"type": "Alabama"
},
{
"id": 2,
"type": "Alaska"
},
{
"id": 3,
"type": "Arizona"
},
{
"id": 4,
"type": "Arkansas"
}
]
},
{
"letter": "C",
"checked": false,
"names": [{
"id": 8,
"type": "California"
},
{
"id": 9,
"type": "Colorado"
},
{
"id": 10,
"type": "Connecticut"
}
]
},
{
"letter": "D",
"checked": false,
"names": [{
"id": 18,
"type": "Delaware"
},
{
"id": 19,
"type": "Denwer"
}
]
}
];
}
Expected output should look like below
Replace your toggleParent function with below given. You can also find solution in the stackblitz: https://stackblitz.com/edit/angular-f5mizr-final-pxdgby
toggleParent(event: any, group: any) {
debugger;
group.checked = event.checked;
console.log("event", event.checked, "group", group, "states value", this.states.value);
let states = this.states.value;
states = states ? states : [];
if (event.checked) {
states.push(...group.names.filter((x: any) => !states.includes(x.type)).map((x: any) => x.type))
} else {
console.log("else", states);
group.names.forEach((x: any) => {
if (states.indexOf(x.type) > -1) {
states.splice(states.indexOf(x.type), 1)
}
});
}
this.states.setValue(states);
console.log("statesvalue", this.states.value);
if (!event.checked) {
this.states.setValue(this.states.value.filter((x: any) => !x.includes(group.names)))
//this.states.setValue([]);
}
console.log("final statesvalue", this.states.value);
this.stateRecord = this.states.value;
}

filtering by pipe: Template parse Error Angular4

its my first time with "pipe" so I think I missed few things:
I have a JSON file which contain data of products. the products can be sort by "ProductTags" - JSON with the tag they can be filter by. also, I have JSON Which contain details about the filter:
"PriceFilter": [
{
"TagId": 20,
"Type": "Budget",
"Value": 5,
"Values": null,
"DisplayText": "$5",
"Order": null
},
{
"TagId": 21,
"Type": "Budget",
"Value": 10,
"Values": null,
"DisplayText": "$10",
"Order": null
}]
product:
"Products": [
{
"ProductId": 206419,
"ProductTitle": "Mom is Fabulous Fruit Box - Good",
"ProductTags": [ 20, 2, 3, 4 ]
}]
I need to order the products using the tags in this way: price
store. html
<table>
<tr *ngFor="let P of PriceFilter | filter : term | orderBy: 'Price'">
<td>{{PriceFilter.DisplayText}}</td>
</tr>
</table>
store component:
stores=[];
products=[];
PriceFilter = [];
GenderFilter =[];
filtered=[];
constructor(private _storeService:StoreService) { }
ngOnInit() {
this._storeService.getProducts()
.subscribe(data =>{
this.products = data.Stores.Products;
this.stores=data.Stores;
this.PriceFilter = data.PriceFilter;
this.GenderFilter = data.GenderFilter;
console.log(data.PriceFilter)
console.log(data.GenderFilter)
console.log(data.Stores)
});
}
filter pipe:
transform(items: any[], term): any {
console.log('term', term);
return term
? items.filter(item => item.ProductTags.indexOf(term) !== -1)
: items;
}
orderBy pipe:
export class OrderbyPipe implements PipeTransform {
transform(items: any[], orderBy: string): any {
console.log('orderdBy', orderBy);
return items.sort((a, b) => {return b[orderBy] - a[orderBy]});
}

Ionic 3 filter nested JSON with ionic searchbar

I have a question how to use ionic searchbar to filter items in a nested JSON object. As I've tried to filter the header item it worked perfectly fine but it does not work for the name wrap inside the brands.
{
"items": [{
"header": "A",
"brands": [{ "name": "Apple", "id": "1" }, { "name": "Adidas", "id": "2" }]
},
{
"header": "B",
"brands": [{ "name": "Bose", "id": "3" }, { "name": "Boss", "id": "4" }, { "name": "Birkenstock", "id": "5" }]
},
{
"header": "M",
"brands": [{ "name": "McDonalds", "id": "6" }]
}
]
}
My search.ts:
private result: any[];
private searchItems: any;
constructor(
public navCtrl: NavController,
public navParams: NavParams,
private http: Http
) {
let localData = this.http.get('assets/search-brand.json').map(res => res.json().items);
localData.subscribe(data => {
this.result = data;
});
this.initializeItems();
}
initializeItems() {
this.searchItems = this.result;
}
getItems(ev: any) {
// Reset items back to all of the items
this.initializeItems();
// set val to the value of the searchbar
let val = ev.target.value;
// if the value is an empty string don't filter the items
if (val && val.trim() != '') {
this.searchItems = this.searchItems.filter((item) => {
return (item.header.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
}
}
My code (search.html):
<ion-searchbar (ionInput)="getItems($event)"></ion-searchbar>
<p>{{test}}</p>
<ion-list *ngFor="let item of searchItems; let i = index">
<ion-list-header>
{{item.header}}
</ion-list-header>
<ion-item *ngFor="let brands of item.brands; let j = index" (click)="selectedBrand(brands.id)">{{brands.name}}</ion-item>
</ion-list>
This one is working for filtering the brands.name it said .toLowerCase() is not a function.
Your JSON data maybe have some element with header == null or does not have brands propertive. So to ensure the search work properly, you should handle these case by if statement. You need to rewrite filter function to get expected output.
Try this:
this.searchItems = this.searchItems.map((item)=>{
if(item && item.brands && item.brands.length > 0){
item.brands = item.brands.filter(brand=>{
if(!brand.name) return false;
return brand.name.toLowerCase().indexOf(val.toLowerCase()) > -1;
});
}
retrun item;
})