I am trying to build a simple accordion in Ionic 2 by pulling data from a json file.
I can iterate through the category and subcategories items to list those, however once a subcategory is clicked, I am not able to fetch the data from the subcategory object and display it (subcategory title) on a detail page. I have looked at many different tutorials/forums but couldn't find how to do this anywhere.
I imagine it is not just an issue with the path but I might need to iterate through the subcategory objects further?
json
{
"results": [
{
"category": "Category 1",
"subCategory": [
{
"title": "subCategory 1.1",
"word": "hello"
},
{
"title": "subCategory 1.2",
"word": "hello"
}
]
},
{
"category": "Category 2",
"subCategory": [
{
"title": "subCategory 2.1",
"word": "hello"
},
{
"title": "subCategory 2.2",
"word": "hello"
}
]
}
]
}
home.html
<ion-header>
<ion-navbar color="primary">
<ion-title>Categories</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item *ngFor="let item of (items | async)?.results">
{{ item.category }}
<div *ngFor="let subItem of item.subCategory">
<button (click)="openDetails(item)">{{ subItem.title }}</button>
</div>
</ion-item>
</ion-list>
</ion-content>
home.ts
export class HomePage {
items: any;
subcategories: any;
constructor(public navCtrl: NavController, public http: Http) {
this.items = this.http.get("assets/data/results-data.json").map(res => res.json());
}
openDetails(item) {
this.navCtrl.push('FilmDetailsPage', {item: item});
}
}
detail.html
<ion-header>
<ion-navbar color="primary">
<ion-title>{{ item.subCategory.title }}</ion-title> // NOT WORKING
</ion-navbar>
</ion-header>
You need to send the subItem i.e. each subcategory and not the item to openDetails() function.
<button (click)="openDetails(subItem)">{{ subItem.title }}</button><!-- here -->
In your details.html,
you can access as
<ion-title>{{ subItem.title }}</ion-title> <!-- make sure the parameter in ts file has name subItem. -->
Related
I would like to read JSON data in my VueJS code.
Here my code :
<template>
{{info}}
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
info: null
};
},
mounted(){
axios
.get('data/products.json')
.then(response => (this.info = response.data.data)),
}
</script>
I have that on the website :
[ { "id": "1000", "code": "1", "name": "Certificats", "description":
"cert Description", "status": "ERROR"}, { "id": "1005", "code": "2",
"name": "Autre", "description": "Product Description", "status":
"ERROR"} ]
I would like to be able to call only for example info.id to print just the id or to use it like an attribute in a v-if or in a v-for.
For example be able to do something like that :
<div :v-for="number in info.id">
{{number}}
</div>
Do you know how to do it ?
Thanks
<div v-for="infoItem in info" :key="infoItem.id">
{{ infoItem.id }}
</div>
Another solution to show only the ids of the errors would be
<div v-for="infoItem in info" :key="infoItem.id">
<div v-if="infoItem.status === 'ERROR'"
{{ infoItem.id }}
</div>
</div>
It's bad practise to combine v-for and v-if in the same line.
I'd suggest you change your v-for loop, and reference whichever key you want to access
<div :v-for="item in info">
{{ item.id }}
{{ item.name }}
</div>
and so on.
I want to display nested list. The structure of the list:
[
{
name: "Level 1A",
children: [
{
name: "Level 2A",
children: [
]
},
{
name: "Level 2B",
children: [
{
name: "Level 3A",
children: [...]
}
]
}
]
},
{
name: "Level 1B",
children: [
{
name: "Level 2A"
children: [...]
}
]
}
]
As you can see we have items with 2 properties: name and children. It could be nestem many many levels down.
The HTML output should be something like this:
<list>
<list-grup name="Level 1A">
<list-item name="Level 2A"></list-item>
<list-item name="Level 2B"></list-item>
</list-grup>
<list-grup name="Level 1B">
<list-item name="Level 2A"></list-item>
</list-grup>
</list>
The only way i found is to display it like this:
<list>
<ng-container *ngFor="let item of list">
<list-group *ngIf="item.children" [item]="item.name">
<ng-container *ngFor="let item1 of item.children">
<list-group [item]="item1.name">
<list-group *ngIf="item1.children" [item]="item1.name">
<ng-container *ngFor="let item2 of item1.children">
...
</ng-container>
</list-group>
</list-group>
</ng-container>
</list-group>
</ng-container>
</list>
But this way is incorrect because I dont want it to be hardcoded because this data will be dynamic.
Can you help me find better solution to display this data? It could be done in template or component.
One possible way is to create a component which represents a single Node (name, children)
first the interface:
export interface Node {
name: string;
children: Node[];
}
component with one #Input() binding
export class NodeComponent implements OnInit {
#Input() node: Node;
html
<li>
<p>{{node.name}}</p>
<ul *ngFor="let item of node.children">
<app-node [node]="item"></app-node>
</ul>
</li>
begin the whole process from:
<ul>
<ng-container *ngFor="let item of list">
<app-node [node]="item"></app-node>
</ng-container>
</ul>
Working Stackblitz
Version with Expand/Collapse support
I am seeking the below result with nested JSON. I am not able to retrive/call keys and values in template dynamically. Refrence link is attached for detail veiw
Angular Code
let checklist = {
"CS": [
{
"id": "1",
"name": "A"
},
{
"id": "2",
"name": "B"
},
{
"id": "3",
"name": "C"
}
],
"Comment": [
{
"id": "1",
"name": "D"
},
{
"id": "2",
"name": "E"
},
{
"id": "3",
"name": "F"
}
]
}
<div *ngFor="let item of Checklist | Key">
{{key}}
<div>{{item}}</div>
</div>
Desired Result
Use keyvalue pipe to loop over Objects within template, Use some css to modify the display but a code like below will serve your need.
<div *ngFor="let item of checklist | keyvalue">
<div>
{{item.key}}
</div>
<div>
<p *ngFor="let eachValue of item.value">
{{eachValue.name}}
</p>
</div>
</div>
https://stackblitz.com/edit/angular-jgwk8n?file=src%2Fapp%2Fapp.component.html
Edit
For angular version < 6, keyvalue pipe doesn't exist. You can create your own custom pipe, maybe like:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'customKeyvalue',
pure: true // keyvalue pipe is actually impure, which means this value would be false
})
export class CustomKeyvaluePipe implements PipeTransform {
transform(inputOb: any): any {
let returnVal = [];
for (let eachKey in inputOb) {
returnVal.push({key: eachKey, value: inputOb[eachKey]})
}
return returnVal
}
}
Now in case your Object changes dynamically without changing its original reference then you would have to make the above pipe as impure (pure: false). This has a downside of being triggered in every change detection.
https://stackblitz.com/edit/angular-jgwk8n?file=src%2Fapp%2Fapp.component.html
You can use Object.keys to get the keys of the object.
This is your component:
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
public checklist: any;
public ObjectKeys = Object.keys;
name = 'Angular';
ngOnInit() {
this.checklist = {
"CS": [
{
"id": "1",
"name": "A"
},
{
"id": "2",
"name": "B"
},
{
"id": "3",
"name": "C"
}
],
"Comment": [
{
"id": "1",
"name": "D"
},
{
"id": "2",
"name": "E"
},
{
"id": "3",
"name": "F"
}
]
};
}
}
This is the HTML:
<table border="1">
<tbody>
<tr *ngFor="let key of ObjectKeys(checklist)">
<td colspan="2" style="border-right-style: solid; border-width: 1px;">
{{ key }}
</td>
<td>
<div *ngFor = "let entry of checklist[key]">
{{ entry.name }}
</div>
</td>
</tr>
</tbody>
</table>
This is the result:
You can add CSS to make it look better, but you get the gist now :)
This is the StackBlitz link which you can edit.
The trick here is to use the display: inline-block and vertical-align: top.
It's similar to xyz example.
<div *ngFor="let item of checklist | keyvalue" >
<div style="display:inline-block;">
{{item.key}}
</div>
<div style="display:inline-block;vertical-align: top;">
<div *ngFor="let eachValue of item.value" >
{{eachValue.name}}
</div>
</div>
</div>
Example: https://angular-hzuexu.stackblitz.io
I'm pulling a list of items and then populate it into a drop down. What i want to achieve is when i select a product, its price should be populated in the quantity textbox.
<ion-item>
<ion-label>Item</ion-label>
<ion-select (ionChange)="getProduct()" [(ngModel)]="product">
<ion-option [value]="item.product" *ngFor="let item of items">{{item.product}}</ion-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Available</ion-label>
<ion-input type="number" [(ngModel)]="quantity"></ion-input>
</ion-item>
JS
items:any;
product:any;
available:any;
quantity:any;
constructor(public navCtrl: NavController, public navParams: NavParams) {
this.items=[
{
"product": "Ideal Milk",
"quantity": '5'
},
{
"product": "Indome",
"quantity": '1'
},
{
"product": "Corn Flakes",
"quantity": '20'
},
{
"product": "Digestive Biscuit",
"quantity": '12'
}
]
}
getProduct(){
}
}
i'm trying to write a function getProduct() which will check for the product selected and the populate in it in the quantity textbox, thats what i want to achieve.
ion-select is binded to product and ion-input to quantity so all you need to do is update quantity when ion-select is changed.
1) Just renamed getProduct() to onSelectValueChange() to be more clear.
2) When product changes onSelectValueChange is fired. Update this.quantity inside onSelectChange(). New value of quantity should automatically reflect ion-input.
.html
<ion-item>
<ion-label>Item</ion-label>
<ion-select (ionChange)="getProduct()" [(ngModel)]="product">
<ion-option [value]="item.product" *ngFor="let item of items">{{item.product}}</ion-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Available</ion-label>
<ion-input type="number" [(ngModel)]="quantity"></ion-input>
</ion-item>
.ts
items:any;
product:any;
available:any;
quantity:any;
constructor(public navCtrl: NavController, public navParams: NavParams) {
this.items=[
{
"product": "Ideal Milk",
"quantity": '5'
},
{
"product": "Indome",
"quantity": '1'
},
{
"product": "Corn Flakes",
"quantity": '20'
},
{
"product": "Digestive Biscuit",
"quantity": '12'
}
]
}
onSelectValueChange(){
this.quantity = this.items.find((element)=>element.product=== this.product).quantity
}
}
I am currently taking my first steps in Ionic, and trying to create an app.
In this example, I have 2 radio button lists (with options 1, 2, 3 and options 4, 5, 6):
I would like both radio buttons 2 and 4 to be checked by default.
Why is only radio button 4 checked?
What am I missing?
Code below.
From the model HTML:
<ion-view view-title="Radio button demo">
<ion-header-bar align-title="left" class="bar-positive">
<h1 class="title">Chosen option: {{item}}, {{item2}}</h1>
</ion-header-bar>
<ion-content>
<ion-list>
<ion-radio ng-repeat="i in items" ng-value="i.Id" ng-model="item.itemval" >{{i.Name}}</ion-radio>
</ion-list>
<ion-list>
<ion-radio ng-repeat="i in items2" ng-value="i.Id" ng-model="item2.itemval" >{{i.Name}}</ion-radio>
</ion-list>
</ion-content>
</ion-view>
From the controller javascript file:
.controller("MainCtrl", function($scope) {
$scope.items = [
{ Id: 1, Name: "Test 1", value: "t1" },
{ Id: 2, Name: "Test 2", value: "t2" },
{ Id: 3, Name: "Test 3", value: "t3" }
];
$scope.items2 = [
{ Id: 4, Name: "Test 4", value: "t4" },
{ Id: 5, Name: "Test 5", value: "t5" },
{ Id: 6, Name: "Test 6", value: "t6" }
];
$scope.item = { itemval: "2" };
$scope.item2 = { itemval: "4" };
});
You need to set the name property on the ion-radio to denote that they belong to different group.
Make these changes in app.html to make it work:
<ion-view view-title="Radio button demo">
<ion-header-bar align-title="left" class="bar-positive">
<h1 class="title">Chosen option: {{item}}, {{item2}}</h1>
</ion-header-bar>
<ion-content>
<ion-list>
<ion-radio ng-repeat="i in items" ng-value="i.Id" ng-model="item.itemval" name="group1">{{i.Name}}</ion-radio>
</ion-list>
<ion-list>
<ion-radio ng-repeat="i in items2" ng-value="i.Id" ng-model="item2.itemval" name="group2">{{i.Name}}</ion-radio>
</ion-list>
</ion-content>
</ion-view>
Edited plunker here: http://plnkr.co/edit/8IU4xskZOiOWcNScprHh?p=preview