I try to get a random object from a local Json file in my Ionic3 App.
Instead of displaying all "questions", "answers" and "hints" from my "cards", I would like to display only the values of a randomly selected card.
This is a dummy project and I am not sure what's the appropriate way to do this.
home.ts
cards: any;
getLocalData() {
this.http.get('assets/data/cards.json').map(res => res.json()).subscribe(res => {
this.cards = res.cards;
this.cards.rd = this.cards[Math.floor(Math.random() * this.cards.length)];
console.log(this.cards.rd);
},
(err) => {
alert("failed loading json data");
})
}
home.html
<button ion-button round (click)="getLocalData()">Charger</button>
<ion-list>
<ion-item *ngFor="let card of cards">
<h2>{{card.question}}</h2>
<h2>{{card.answer}}</h2>
<h2>{{card.hint}}</h2>
</ion-item>
</ion-list>
cards.json
{
"cards": [
{
"id": "1",
"question": "question 1",
"answer": "reponse 1",
"hint": "hint 1"
},
{
"id": "2",
"question": "question 2",
"answer": "reponse 2",
"hint": "hint 2"
},
{
"id": "3",
"question": "question 3",
"answer": "reponse 3",
"hint": "hint 3"
}
]
}
Related
I received the following object (Survay) JSON format from server
/**************************************/
{
"id": 870,
"title": "test survay ",
"questions": [
{
"id": 871,
"data": "question data 1"
},
{
"id": 874,
"data": "question data 2"
},
{
"id": 877,
"data": "question data 3"
}
],
"user": {
"id": 788,
"name": "mohamed",
"answres": [
{
"data":"answere question 1"
},
{
"data":"answere question 2"
},
{
"data":"answere question 3"
}
]
}
}
I used the following code
getSurvayByid(id: number) {
const headers = new HttpHeaders({
'Authorization': this.loadToken(),
'Content-Type': 'application/json'
});
return this.http.get<Survay>(this.host + "/survay/" + id, { headers: headers })
.pipe(map(resp => resp));
}
I would like to change this format as it’s displayed:
My question:how I can get this format using the Rxjs operators ?
(map, take, pipe...) and change the method getSurvayByid(id: number)
{
"id": 870,
"title": "test survay ",
"questions": [
{
"id": 871,
"data": "question data 1",
"answer":"answere question 1"
},
{
"id": 874,
"data": "question data 2",
"answer":"answere question 2"
},
{
"id": 877,
"data": "question data 3",
"answer":"answere question 3"
}
],
"user": {
"id": 788,
"name": "mohamed"
}
}
Assuming the answers are in correct order, you can do it like this:
return this.http.get<Survay>(this.host + "/survay/" + id, { headers: headers }).pipe(
map((resp: Survay): Survay => {
resp.questions.forEach((question, i) => question.answer = resp.answers.length == 0 ? '' : resp.answers[i].data);
return resp;
})
);
I'm assuming the return type is also Survay. Please replace with correct return type.
getSurvayByid(id).toPromise().then(s => {
s.questions.forEach((q,i)=>{this.answers=s.user.answres!
if(this.answers.length==0){
q.answer="";
}
else {
q.answer=this.answers[i].data;
}
})
}
I would like to get each key value pair in the results object from my api to display on my front-end. ie(category, type, difficulty, questions correct_answer) I have the service and components set up correctly and all i need to do is fetch the json and display each pair. The method name is called fetchQuestions as seen below. I was able to successfully get data by just simply calling it the same way I did fetchPeople but the json format is not the same so it's not displaying. I then tried something else but that's not working either. How can I acheive displaying this?
People.service
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '#angular/common/http';
import { map } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class PeopleService {
constructor(private http: HttpClient) { }
//this works like a charm as it is just a simple array
fetchPeople(): Observable <Object> {
return this.http.get('/assets/data/people.json')
}
// this doesn't work as the json from the api below is in a different
// json format. Plus I need to return all value pairs
fetchQuestions(): Observable <Object> {
return this.http.get('https://opentdb.com/api.php?
amount=10&difficulty=hard&type=boolean').map(res =>
res.json().results).subscribe(data => {
console.log(data););
}
}
API
https://opentdb.com/api.php?amount=10&difficulty=hard&type=boolean
{
"response_code": 0,
"results": [
{
"category": "Vehicles",
"type": "boolean",
"difficulty": "hard",
"question": "In 1993 Swedish car manufacturer Saab experimented
with replacing the steering wheel with a joystick in a Saab 9000.",
"correct_answer": "True",
"incorrect_answers": [
"False"
]
},
{
"category": "History",
"type": "boolean",
"difficulty": "hard",
"question": "Japan was part of the Allied Powers during World War
I.",
"correct_answer": "True",
"incorrect_answers": [
"False"
]
},
{
"category": "History",
"type": "boolean",
"difficulty": "hard",
"question": "The Kingdom of Prussia briefly held land in Estonia.",
"correct_answer": "False",
"incorrect_answers": [
"True"
]
},
{
"category": "Science: Mathematics",
"type": "boolean",
"difficulty": "hard",
"question": "The binary number "101001101" is equivalent
to the Decimal number "334"",
"correct_answer": "False",
"incorrect_answers": [
"True"
]
},
{
"category": "Entertainment: Video Games",
"type": "boolean",
"difficulty": "hard",
"question": "TF2: Sentry rocket damage falloff is calculated based
on the distance between the sentry and the enemy, not the engineer
and the enemy",
"correct_answer": "False",
"incorrect_answers": [
"True"
]
},
{
"category": "Entertainment: Video Games",
"type": "boolean",
"difficulty": "hard",
"question": "The names of Roxas's Keyblades in Kingdom Hearts
are "Oathkeeper" and "Oblivion".",
"correct_answer": "True",
"incorrect_answers": [
"False"
]
},
{
"category": "Entertainment: Music",
"type": "boolean",
"difficulty": "hard",
"question": "The band STRFKR was also briefly known as Pyramiddd.",
"correct_answer": "True",
"incorrect_answers": [
"False"
]
},
{
"category": "Entertainment: Books",
"type": "boolean",
"difficulty": "hard",
"question": "Harry Potter was born on July 31st, 1980.",
"correct_answer": "True",
"incorrect_answers": [
"False"
]
},
{
"category": "Entertainment: Japanese Anime & Manga",
"type": "boolean",
"difficulty": "hard",
"question": "Druid is a mage class in "Log Horizon".",
"correct_answer": "False",
"incorrect_answers": [
"True"
]
},
{
"category": "Geography",
"type": "boolean",
"difficulty": "hard",
"question": "The two largest ethnic groups of Belgium are Flemish and Walloon. ",
"correct_answer": "True",
"incorrect_answers": [
"False"
]
}
]
}
People.page.ts
import { Component, OnInit } from '#angular/core';
import { PeopleService } from './../../providers/people.service'
#Component({
selector: 'app-people',
templateUrl: './people.page.html',
styleUrls: ['./people.page.scss'],
})
export class PeoplePage implements OnInit {
people$;
results$;
constructor(private peopleService:PeopleService) { }
fetchPeople(){
this.people$ = this.peopleService.fetchPeople();
}
fetchQuestions(){
this.results$ = this.peopleService.fetchQuestions()
}
ngOnInit() {
}
}
People.page.html
<ion-toolbar>
<ion-title>people</ion-title>
</ion-toolbar>
</ion-header>
<ion-button (click) ="fetchPeople()" color="primary">Primary</ion-
button>
<ion-list>
<ion-item *ngFor="let person of people$ | async">{{person.name}}.
</ion-item>
</ion-list>
<ion-button (click) ="fetchQuestions()"
color="primary">Secondary</ion-button>
<ion-list>
<ion-item *ngFor="let result of results$ | async">.
{{result.category}}</ion-item>
<ion-item *ngFor="let result of results$ | async">
{{result.questions}}</ion-item>
<ion-item *ngFor="let result of results$ | async">
{{result.difficulty}}</ion-item>
<ion-item *ngFor="let result of results$ | async">
{{result.correct_answer}}</ion-item>
</ion-list>
<ion-content>
<ion-button color="primary">Primary</ion-button>
</ion-content>
The HTTP GET is a cold observable. As such each async will fire an individual request. Besides you aren't actually returning the observable from the fetchQuestions() function. The subscription should be removed.
You could also use Angular HttpParams to set the query parameters and do things the Angular way.
Try the following
Service
import { HttpClient, HttpParams } from '#angular/common/http';
fetchQuestions(): Observable<any> {
const params = new HttpParams()
.set('amount', '10')
.set('difficulty', 'hard')
.set('type', 'boolean');
return this.http.get('https://opentdb.com/api.php', { params: params })
.pipe(map(res => res.results));
}
Template
<ng-container *ngFor="let result of results$ | async">
<ion-list>
<ion-item>{{result.category}}</ion-item>
<ion-item>{{result.question}}</ion-item>
<ion-item>{{result.difficulty}}</ion-item>
<ion-item>{{result.correct_answer}}</ion-item>
</ion-list>
</ng-container>
I also noticed a small type. result.questions should actually be result.question.
More details about hot vs cold observables: https://blog.thoughtram.io/angular/2016/06/16/cold-vs-hot-observables.html
Working example: Stackblitz
In this view of the mobile application I need to group the data that are returned by json api group by date !!
how to groupby date the data json api with ionic 2
!
In this view of the mobile application I need to group the data that are returned by json api group by date !!
how to groupby date the data json api with ionic 2
!
Json API :
course_cheval: [
{
CourseHasCheval: {
id: "1461",
course_id: "460",
cheval_id: "90",
rang: "2",
temps: "TETE",
jockey_id: "30",
poids: "57",
part_jokey: "367.000",
entraineur_id: "6",
part_entraineur: "440.000",
propritaire: "GHARBI. MED",
part_propritaire: "4400.000",
eleveur_id: "47",
part_eleveur: "2200.000"
},
Course: {
id: "460",
date: "2012-06-24",
nom_du_prix: "GODOLPHIN ARABIAN",
allocation: "20000",
hippodrome_id: "2",
jouree: "36",
categorie_id: "1",
distance: "1600",
},
{
CourseHasCheval: {
id: "1412",
course_id: "445",
cheval_id: "90",
rang: "1",
temps: "1.53''8/10",
jockey_id: "3",
poids: "56",
part_jokey: "660.000",
entraineur_id: "6",
part_entraineur: "660.000",
propritaire: "GHARBI. MED",
part_propritaire: "6600.000",
eleveur_id: "47",
part_eleveur: "3300.000"
},
Course: {
id: "445",
date: "2012-10-21",
nom_du_prix: "RIDHA BEN EZZEDINE",
allocation: "12000",
hippodrome_id: "2",
jouree: "49",
categorie_id: "2",
distance: "1600",
nbre_partant: "9",
}
}]
<ion-grid *ngSwitchCase="'Compteurs'">
<ion-row *ngFor="let m of members ">
<ion-col width-20 >
{{m.Course.date | date : "yyyy"}}
</ion-col>
<ion-col width-30>
{{m.Course.nom_du_prix}}
</ion-col>
<ion-col width-20>
GR.{{m.Course.categorie_id}}
</ion-col>
<ion-col width-30>
{{m.Course.allocation}}
</ion-col>
</ion-row>
Your array has some objects without a date property which complicates this slightly so lets start with a simpler example where everything has a date property like so
[
{
"name": "Philosophy 212: Ethics and Applications",
"date": "2007-12-12"
},
{
"name": "JavaScript Fundamentals",
"date": "2007-12-12"
},
{
"name": "Math 364: Linear Algebra",
"date": "2017-01-15"
}
]
We can write a groupByDate function that handles the basic case
function groupByDate<T extends {date: string}>(datedValues: T[]) {
return datedValues.reduce((groups, dated) => {
const key = dated.date;
if (groups[key]) {
groups[key].push(dated);
} else {
groups[key] = [dated];
}
return groups;
}, {} as {[key string]: T[]});
}
Here it is in a snippet (sans types)
var courses = [
{
"name": "Philosophy 212: Ethics and Applications",
"date": "2007-12-12"
},
{
"name": "JavaScript Fundamentals",
"date": "2007-12-12"
},
{
"name": "Math 364: Linear Algebra",
"date": "2017-01-15"
}
];
function groupByDate(datedValues) {
return datedValues.reduce((groups, dated) => {
const key = dated.date;
if (groups[key]) {
groups[key].push(dated);
} else {
groups[key] = [dated];
}
return groups;
}, {});
}
console.log(groupByDate(courses));
we can make this much more useful with by writing a more generic groupBy function that groups by any string value.
function groupBy<T>(values: T[], keyOrKeySelector: keyof T | ((value: T) => string)) {
return values.reduce((groups, value) => {
const key = typeof keySelector === 'function'
? keyOrKeySelector(value)
: value[keyOrKeySelector];
if (groups[key]) {
groups[key].push(value);
} else {
groups[key] = [value];
}
return groups;
}, {} as {[key string]: T[]});
});
}
Either of these can be made into a pipe with minimal effort if you want to use them inside of an angular template.
I'm rendering some checkboxes based on an array and using a data attribute as the v-model. I'm using Vue2.
However, I end up having all checkboxes checked for some reason, when the value of the v-model equals 1 (I guess it treats it as a bool instead of a number).
I tried v-model.number - without any luck. What am I doing wrong?
My template:
<div v-for="category in categories">
<input
type="checkbox"
v-model.number="item.category"
:id="'category_' + category.id"
:value="category.id"
#change="save"
/>
<label>{{ item.category }} : {{ category.id }}</label>
</div>
Model Data (item.category):
1
Categories:
[
{
"id": 2,
"name": "news Category 0"
},
{
"id": 7,
"name": "news Category 1"
},
{
"id": 12,
"name": "news Category 2"
},
{
"id": 17,
"name": "news Category 3"
},
{
"id": 22,
"name": "news Category 4"
},
{
"id": 27,
"name": "news Category 5"
},
// other values
]
Screenshot (Ive added item.category and category.id as label text to make it more clear):
As you are using Multiple checkboxes, you have to give an array in v-model, so your item.category has to be an array: [1].
See the working fiddle: https://jsfiddle.net/mimani/y36f3cbm/
var demo = new Vue({
el: '#demo',
data() {
return {
categories: [{
"id": 2,
"name": "news Category 0"
}, {
"id": 92,
"name": "news Category 8"
}, {
"id": 97,
"name": "news Category 9"
}],
item: {
category: [1]
}
};
}
})
I'm new to ionic and I want to be able to extend a simple json data set to include lists within an array:
My json file looks like this:
angular.module('starter.services', [])
/** A simple example service that returns some data. */
.factory('Bands', function() {
var bands = [
{"id": "0", name: 'U2', nationality: 'Irish', category: 'Rock', pic: "U2.jpg", url:"www.u2.com" },
{
"albums":
{"album"
[
{ "id": "101", name:"Songs Of Innocence", year:"2014", pic: "u2_soi_cover.jpg" },
{ "id": "102", name:"No Line On The Horizon", year:"2009", pic: "u2_nloth_cover.jpg" },
{ "id": "103", name:"How To Dismantle An Atomic Bomb", year:"2004", pic: "u2_htdaab_cover.jpg" },
]
},
},
{"id": "1", name: 'Silverchair', nationality: 'Australian', category: 'Grunge', pic: "silverchair.jpg", url:"www.silverchair.com/" },
{
"albums":
{"album"
[
{ "id": "102", name:"Frogstomp", year:"1995", pic: "sc_frogstomp_cover.jpg" },
]
},
},
];
return {
all: function() {
return bandss;
},
get: function(bandId) {
// Simple index lookup
return bands[bandId];
}
}
})
So I have been able to return the list of bands using a repeat and pass the band id to display individual band details.
I want to no extend the band page to it to return the album list details so I'm guessing it would be something like this, but I need some help understanding how to get the list out of the array for a specific band id.
<ion-content>
<div class="details">
<img src="pics/bands/{{band.pic }}" />
<h2>{{band.name}}</h2>
<p>{{band.nationality}}</p>
</div>
<ion-list>
<ion-item ng-repeat="album in albums" type="item-text-wrap" >
<h2>{{album.name}}</h2>
<p>{{album.year}}</p>
</ion-item>
</ion-list>
</ion-content>
Any help to point me in the right direction would be great.
You need to change the json format, move the "albums" into the "bands", like this:
[
{
"id": "0",
"name": "U2",
"nationality": "Irish",
"category": "Rock",
"pic": "U2.jpg",
"url": "www.u2.com",
"albums": [
{
"id"": "101",
"name": "SongsOfInnocence",
"year": "2014",
"pic": "u2_soi_cover.jpg"
}
]
}
]
Now in the ng-repeat of your view:
<ion-item ng-repeat="album in band.albums" type="item-text-wrap" >
<h2>{{album.name}}</h2>
<p>{{album.year}}</p>
</ion-item>