Skip to content

Instantly share code, notes, and snippets.

@adash333
Last active June 30, 2018 13:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adash333/03b6c66e7a219fb7dcbfdd33ed0c5b43 to your computer and use it in GitHub Desktop.
Save adash333/03b6c66e7a219fb7dcbfdd33ed0c5b43 to your computer and use it in GitHub Desktop.
ionic3-firebase-quiz-ranking
// app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';
import { HttpClientModule } from '@angular/common/http';
// import AF2 modules
import { AngularFireModule } from 'angularfire2';
import { AngularFireDatabaseModule } from 'angularfire2/database';
import { environment } from '../environments/environment';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { DataProvider } from '../providers/data/data';
//import { FlashCardComponent } from '../components/flash-card/flash-card';
import { ComponentsModule } from '../components/components.module';
@NgModule({
declarations: [
MyApp,
HomePage,
//FlashCardComponent
],
imports: [
BrowserModule,
IonicModule.forRoot(MyApp),
HttpClientModule,
ComponentsModule,
AngularFireModule.initializeApp(environment.firebase),
AngularFireDatabaseModule
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage
],
providers: [
StatusBar,
SplashScreen,
{provide: ErrorHandler, useClass: IonicErrorHandler},
DataProvider
]
})
export class AppModule {}
{
"questions": [
{
"flashCardFront": "<img src='assets/imgs/helicopter.png' />",
"flashCardBack": "ヘリコプター",
"flashCardFlipped": false,
"questionText": "これはなに?",
"answers": [
{"answer": "ヘリコプター", "correct": true, "selected": false},
{"answer": "ひこうき", "correct": false, "selected": false},
{"answer": "トラック", "correct": false, "selected": false}
]
},
{
"flashCardFront": "<img src='assets/imgs/plane.png' />",
"flashCardBack": "ひこうき",
"flashCardFlipped": false,
"questionText": "これはなに?",
"answers": [
{"answer": "スポーツカー", "correct": false, "selected": false},
{"answer": "ひこうき", "correct": true, "selected": false},
{"answer": "オートバイ", "correct": false, "selected": false}
]
},
{
"flashCardFront": "<img src='assets/imgs/truck.png' />",
"flashCardBack": "トラック",
"flashCardFlipped": false,
"questionText": "これはなに?",
"answers": [
{"answer": "ふね", "correct": false, "selected": false},
{"answer": "でんしゃ", "correct": false, "selected": false},
{"answer": "トラック", "correct": true, "selected": false}
]
}
]
}
<ion-content>
<ion-slides #slides>
<ion-slide class="start-slide">
<h3>Ionic3-kids-quiz</h3>
<form (ngSubmit)="nextSlide()">
<ion-list>
<ion-item>
<ion-label floating>Enter your Nickname</ion-label>
<ion-input type="text" [(ngModel)]="data.user" name="user" required="" ></ion-input>
</ion-item>
<ion-item>
<button ion-button color="primary" full>Start!</button>
</ion-item>
</ion-list>
</form>
<br><br>
<button ion-button color="secondary" outline [navPush]="'RankingPage'">ランキング</button>
</ion-slide>
<ion-slide *ngFor="let question of questions; let i = index;">
<h3>Question {{i+1}}</h3>
<ion-item no-lines>
<flash-card [isFlipped]="question.flashCardFlipped">
<div class="flash-card-front" [innerHTML]="question.flashCardFront"></div>
<div class="flash-card-back" [innerHTML]="question.flashCardBack"></div>
</flash-card>
</ion-item>
<h3>{{question.questionText}}</h3>
<ion-list no-lines radio-group>
<ion-item *ngFor="let answer of question.answers; let i = index">
<ion-label>{{i+1}}.{{answer.answer}} </ion-label>
<ion-radio (click)="selectAnswer(answer, question)" [checked]="answer.selected" [disabled]="hasAnswered"></ion-radio>
</ion-item>
</ion-list>
</ion-slide>
<ion-slide>
<h2>{{data.user}}さんのスコア:{{score}}</h2>
<button (click)="saveScore()" ion-button full color="secondary">スコアを保存</button>
<br><br>
<button ion-button color="secondary" outline [navPush]="'RankingPage'">ランキング</button>
<br><br>
<button (click)="restartQuiz()" ion-button full color="primary">クイズに再チャレンジ
</button>
</ion-slide>
</ion-slides>
</ion-content>
page-home {
ion-slide {
align-items: flex-start;
}
ion-item {
margin-bottom: 5px;
font-size: 1.2em;
background-color: map-get($colors, primary);
}
flash-card {
color: #000;
img {
width: 70%;
height: auto;
}
}
.start-slide {
justify-content: center;
align-items: center;
button {
font-size: 1.3em;
font-weight: bold;
}
}
}
import { Component, ViewChild } from '@angular/core';
import { NavController, AlertController } from 'ionic-angular';
import { DataProvider } from '../../providers/data/data';
import { AngularFireDatabase, AngularFireList } from 'angularfire2/database';
//import { QuizScore } from '../../models/quizScore';
import * as firebase from 'Firebase';
@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
data = { user:"", score:"" };
public quizScores: AngularFireList<{}>;
//public quizScore: QuizScore;
@ViewChild('slides') slides: any;
hasAnswered: boolean = false;
user: string;
score: number = 0;
slideOptions: any;
//flashCardFlipped: boolean = false;
questions: any;
constructor(
public navCtrl: NavController,
public dataService: DataProvider,
db: AngularFireDatabase,
private alertCtrl: AlertController
) {
this.quizScores = db.list('quizScores');
}
ionViewDidLoad() {
this.slides.lockSwipes(true);
this.dataService.load().then((data) => {
data.map((question) => {
let originalOrder = question.answers;
question.answers = this.randomizeAnswers(originalOrder);
return question;
});
this.questions = data;
});
}
nextSlide() {
this.slides.lockSwipes(false);
this.slides.slideNext();
this.slides.lockSwipes(true);
}
selectAnswer(answer, question) {
this.hasAnswered = true;
answer.selected = true;
question.flashCardFlipped = true;
if(answer.correct) {
this.score++;
}
setTimeout(() => {
this.hasAnswered = false;
this.nextSlide();
answer.selected = false;
question.flashCardFlipped = false;
}, 3000);
}
randomizeAnswers(rawAnswers: any[]): any[] {
for(let i = rawAnswers.length -1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
let temp = rawAnswers[i];
rawAnswers[i] = rawAnswers[j];
rawAnswers[j] = temp;
}
return rawAnswers;
}
restartQuiz() {
this.score = 0;
this.slides.lockSwipes(false);
this.slides.slideTo(1, 1000);
this.slides.lockSwipes(true);
}
//firebaseへのデータ保存
saveScore() {
let newData = firebase.database().ref('quizscores').push();
newData.set({
user:this.data.user,
score:this.score,
date:Date()
})
let alert = this.alertCtrl.create({
title: 'スコアを保存しました',
buttons: ['OK']
});
alert.present();
}
}
export class QuizScore {
user: string;
score: number;
//date: number;
constructor(user: string, score: number) {
this.user = user;
this.score = score;
//this.date = Date.now();
}
// 取得した日付を反映
//setData(date: number): QuizScore {
// this.date = date;
// return this;
//}
}
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import 'rxjs/add/operator/map';
//import { Observable } from 'rxjs/observable';
@Injectable()
export class DataProvider {
data: any;
constructor(public http: HttpClient) {
console.log('Hello DataProvider Provider');
}
load() {
if(this.data) {
return Promise.resolve(this.data);
}
return new Promise(resolve => {
this.http.get('assets/data/questions.json').subscribe(data => {
this.data = data["questions"];
resolve(this.data);
});
});
}
}
<ion-header>
<ion-navbar color="primary">
<ion-title>
ランキング
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-grid>
<ion-row text-center nowrap class="top">
<ion-col col-2>
<div>順位</div>
</ion-col>
<ion-col col-8>
<div>お名前</div>
</ion-col>
<ion-col col-2>
<div>記録</div>
</ion-col>
</ion-row>
<ion-row *ngFor="let item of quizScores; index as i">
<ion-col col-2>
<div>{{i + 1}}位</div>
</ion-col>
<ion-col col-8>
<div>{{item.user}}</div>
</ion-col>
<ion-col col-2>
<div>{{item.score}}点</div>
</ion-col>
</ion-row>
</ion-grid>
</ion-content>
page-ranking {
ion-grid ion-row {
background-color: white;
border: 0px solid #e6e9ee;
//border-radius: 2px;
padding: 5px;
text-align: center;
//border-bottom: solid 1px black;
}
ion-grid .top {
border-bottom: solid 2px orange;
}
}
import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { AngularFireDatabase, AngularFireList} from 'angularfire2/database';
import { QuizScore } from '../../models/quizScore';
@IonicPage()
@Component({
selector: 'page-ranking',
templateUrl: 'ranking.html',
})
export class RankingPage {
public FB_quizScores: AngularFireList<{}>;
public quizScores: QuizScore[] = [];
constructor(
public navCtrl: NavController,
public navParams: NavParams,
public db: AngularFireDatabase
) {
this.FB_quizScores = db.list('/quizscores');
this.FB_quizScores.snapshotChanges().subscribe((actions: any[]) => {
this.quizScores = [];
actions.forEach((action: any) => {
// 取得したデータを反映
const val = action.payload.val()
this.quizScores.push(new QuizScore(val.user, val.score));
});
this.quizScores.sort( function(a, b) {
return a.score > b.score ? -1 : 1;
});
});
}
ionViewDidLoad() {
console.log('ionViewDidLoad RankingPage');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment