Angular2: EXCEPTION: Attempt to use a dehydrated detector: QuizzPage_2 -> select - exception

I'm having an issue in my ionic2/angular2 app.
I'm building a quizz app, in which the user is prompted to answer questions, on radio choices.
The moment the first choice is made, I get this error:
EXCEPTION: Attempt to use a dehydrated detector: QuizzPage_2 -> select
The console:
The code breaks here when I debug Pause On Exception:
SafeSubscriber.prototype.__tryOrUnsub = function (fn, value) {
try {
fn.call(this._context, value);
}
catch (err) {
this.unsubscribe();
throw err;
Here are my main files:
The page.html:
(...)
<ion-item radio-group *ngFor="#choice of quizz.getChoices()">
<ion-label>
<p courant>{{ choice }}</p>
</ion-label>
<ion-radio (click)="onSubmit($event, choice)">
{{ choice }}
</ion-radio>
</ion-item>
(...)
My page.ts:
import {Page, NavController, NavParams} from 'ionic-angular';
import {Quizz} from '../models/quizz';
import {QuizzResultsPage} from './quizz-results.page';
import quizzes from '../../data/quizzes';
#Page({
templateUrl: 'build/pages/quizz/Quizzes/templates/quizz.page.html',
})
export class QuizzPage {
nav;
quizz;
constructor(nav: NavController, params: NavParams) {
this.nav = nav;
// Load the quizz with passed topicId from the params.get (import{NavParams})
this.quizz = this.loadQuizz(params.get('topicId'));
}
loadQuizz(topicId) {
// cont quizz = data (import quizzes from '../../data/quizzes';)
const quizz = quizzes.filter((quizz) => {
return quizz.topicId === topicId;
})[0];
return new Quizz(quizz);
}
onSubmit(event, answer) {
this.quizz.submitAnswer(answer);
if (this.quizz.isCompleted) {
this.nav.push(QuizzResultsPage, {
quizz: this.quizz
});
}
}
}
I'm still able to finish the quizz, but in the end in my result page, I can't go back or restart the quizz, and my navbar breaks...
My resultpage.html:
(...)
<ion-card-content>
<p>
Votre score:
<span primary>{{ quizz.getScore() }}</span> / <b>{{ quizz.getGradingScale() }}</b>
</p>
</ion-card-content>
</ion-card>
<!-- Questions with answers -->
<div [hidden]="quizz.isPerfect()">
<ion-card *ngFor="#i of quizz.items" style="background-color:aliceblue;">
<ion-card-header>
<b bluegray text-uppercase>Question: </b>
<p>
{{ i.question }}
</p>
</ion-card-header>
<ion-card-content>
<b bluegray text-uppercase>RĂ©ponse:</b>
<p courant text-justify>{{ i.answer }}</p>
</ion-card-content>
</ion-card>
</div>
<!-- Exit & Restart -->
<div padding style="width:70%; margin: 0 auto">
<button item-right block (click)="onHomeClicked($event)">Recommencer
<ion-icon name="refresh-circle"></ion-icon>
</button>
<button itel-left block (click)="onGoHome($event)">Accueil
<ion-icon name="home"></ion-icon>
</button>
</div>
</ion-content>
And finally my results.ts:
import {Page, NavController, NavParams} from 'ionic-angular';
import {TopicsPage} from '../../topics';
import {Home} from '../../../home/home';
#Page({
templateUrl: 'build/pages/quizz/Quizzes/templates/quizz-results.page.html',
})
export class QuizzResultsPage {
nav;
quizz;
constructor(nav: NavController, params: NavParams) {
this.quizz = params.get('quizz');
this.nav = nav;
this.nav.pop();
}
onHomeClicked(event) {
this.nav.setRoot(TopicsPage);
this.nav.pop(TopicsPage);
}
onGoHome(event){
this.nav.setRoot(Home);
this.nav.pop(Home);
}
Someone have an idea? Thanks

Related

Ionic3 coding- trying to retrieve quote of the day

Code in provider.ts file :
getQuotes() : Observable<any> {
return this.http.get("");
}
1st method: The coding in home.ts file of the page where the quote needs to be displayed:
quote:string;
author:string;
constructor(public navCtrl: NavController, private qp: QuoteProvider) { }
ionViewDidLoad()
{
this.qp.getQuotes().subscribe(data => {
this.quote = data.quote;
this.author = data.author;
});
}
.html code tried this nothing worked:
<h2> {{ quote}} </h2>
<h3> {{ author }}</h3>
</ion-item> </ion-list>
2nd method tried; tried using array though the data is not in array format
home.ts file:
export class HomePage { quote:any[]; author:any[];
constructor(public navCtrl: NavController, private qp: QuoteProvider) { }
ionViewDidLoad() {
this.qp.getQuotes().subscribe(data => {
this.quote = data.quotes;
this.author = data.quotes;
});
}
.html file code*:
<ion-list>
<ion-item *ngFor = "let q of quote">
<h2> {{ q.quote}} </h2>
<h3> {{q.author }}</h3>
</ion-item>
</ion-list>
In provider.ts you should do the following:
import 'rxjs/add/operator/map';
getQuotes(){
return this.http.get("").map(res => res.json());
}
Then in home.ts
ionViewDidLoad()
{
this.qp.getQuotes().subscribe(data => {
this.quote = data.contents.quotes[0].quote;
this.author = data.contents.quotes[0].author;
// This is assuming the quotes array always has only one quote
});
}
EDIT
As Prerak Tiwari commented, you also need to remove the for loop in home.html:
<ion-list>
<ion-item>
<h2> {{ quote }} </h2>
<h3> {{ author }}</h3>
</ion-item>
</ion-list>

Chat page socket.io ionic error

I have small problem with my chat page :) wanted to do some chat application
I have login that is working but when I click to button chat it's crashing. I am beginner so maybe I can't see correctly. It's in Ionic 3
Home.ts
import { Component } from '#angular/core';
import { NavController, IonicPage } from 'ionic-angular';
import { Auth } from '#ionic/cloud-angular';
import { User } from '#ionic/cloud-angular';
import { LoginPage } from '../login/login';
import { About } from '../about/about';
import { ChatPage } from '../chat/chat';
#IonicPage()
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public navCtrl: NavController, public auth: Auth, public user: User) {
console.log(user);
}
logout() {
this.auth.logout();
this.navCtrl.setRoot(LoginPage);
}
about(){
this.navCtrl.setRoot(About);
this.navCtrl.push(About);
}
chat(){
this.navCtrl.setRoot(ChatPage);
this.navCtrl.push(ChatPage);
}
}
home.html
<ion-header>
<ion-navbar>
<ion-title>
Home
</ion-title>
<ion-buttons end>
<button ion-button icon-only (click)="logout()">
<ion-icon name="exit"></ion-icon>
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content padding>
<h2>Welcome back, {{ user.details.name }}</h2>
<p>
<button ion-button color="secondary" block>Something</button>
</p>
<p>
<button ion-button color="secondary" block (click)="chatPage()">Chat</button>
</p>
<p>
<button ion-button color="secondary" block (click)="about()">About</button>
</p>
</ion-content>
chat.ts
import { Component, NgZone, ViewChild } from '#angular/core';
import { NavController, Content } from 'ionic-angular';
import { Validators, FormBuilder } from '#angular/forms';
import * as io from 'socket.io-client';
import { HomePage } from '../home/home';
#Component({
selector: 'page-chat',
templateUrl: 'chat.html'
})
export class ChatPage {
public chatForm: any;
#ViewChild(Content) content: Content;
messages:any = [];
socketHost: string = "http://localhost:3000/";
socket:any;
chat:any;
username:string;
zone:any;
chatField: any;
constructor(public navCtrl: NavController, private fb: FormBuilder){
this.socket = io.content(this.socketHost);
this.zone = new NgZone({enableLongStackTrace: false});
this.socket.on("chat me", (msg) =>{
this.zone.run (() =>{
this.messages.push(msg);
this.content.scrollToBottom();
});
});
this.chatForm = fb.group({
'chatField': ['', Validators.compose([Validators.required])],
});
this.chatField = this.chatForm.controls['chatField'];
}
chatSend(v) {
let data = {
message: v.chatText,
username: this.username
}
this.socket.emit('new message', data);
this.chat = "";
}
onSubmit(value: string): void {
if(this.chatForm.valid) {
}
}
}
chat.html
<ion-header>
<ion-navbar>
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>Chat</ion-title>
</ion-navbar>
<ion-input [(ngModel)] = "username" placeholder="Username"> </ion-input>
</ion-header>
<ion-content class="chat">
<ion-list>
<div *ngFor="let data of messages">
<ion-item *ngIf="username === data.username" style="border-right: solid 5px red;">
<p class="chat-text" item-left>
<strong> {{data.username}}: </strong>
{{data.message}}
</p>
<p class="chat-time" item-right>
{{data.date | date:'dd/MM/yyyy'}}
</p>
</ion-item>
<ion-item *ngIf="username !== data.username" style="border-right: solid 5px green;">
<p class="chat-text" item-left>
<strong> {{data.username}}: </strong>
{{data.message}}
</p>
<p class="chat-time" item-right>
{{data.date | date:'dd/MM/yyyy'}}
</p>
</ion-item>
</div>
</ion-list>
</ion-content>
<ion-footer>
<form padding [formGroup]="chatForm" (ngSubmit)="onSubmit(chatForm.value)">
<ion-item>
<ion-input [(ngModel)]="chatField" name="chatText" required placeholder="type here....."></ion-input>
</ion-item>
<br/><br/>
<button type="submit" ion-button [disabled]="!chatForm.valid" block>Send</button>
</form>
</ion-footer>
the error that I am getting is
Runtime Error
co.chatPage is not a function
Stack
TypeError: co.chatPage is not a function
at Object.eval [as handleEvent] (ng:///AppModule/HomePage.ngfactory.js:290:24)
at handleEvent (http://localhost:8100/build/main.js:12302:138)
at callWithDebugContext (http://localhost:8100/build/main.js:13510:42)
at Object.debugHandleEvent [as handleEvent] (http://localhost:8100/build/main.js:13098:12)
at dispatchEvent (http://localhost:8100/build/main.js:9277:21)
at http://localhost:8100/build/main.js:9867:38
at HTMLButtonElement.<anonymous> (http://localhost:8100/build/main.js:35897:53)
at t.invokeTask (http://localhost:8100/build/polyfills.js:3:12256)
at Object.onInvokeTask (http://localhost:8100/build/main.js:4613:37)
at t.invokeTask (http://localhost:8100/build/polyfills.js:3:12177)
at n.runTask (http://localhost:8100/build/polyfills.js:3:7153)
at HTMLButtonElement.invoke (http://localhost:8100/build/polyfills.js:3:13213)
Ionic Framework: 3.1.1
Ionic App Scripts: 1.3.7
Angular Core: 4.0.2
Angular Compiler CLI: 4.0.2
Node: 7.2.0
OS Platform: Windows 10
Navigator Platform: Win32
User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) App
The problem is you have called (click)="chatPage()" in your template and the function in your HomePage.ts is chat().
Do:
<button ion-button color="secondary" block (click)="chat()">Chat</button>
Side Note:
You dont have to do both push and setRoot.
setRoot will create an new navigation stack and set the particular page as Root.
push will push the page onto the current navigation stack.
Use one of them based on your requirement.

Ionic 2 will not let me loop over an object of objects using *ngFor

I am developing an app where users can search for classified ads.
However, I am unable to display the search results.
Here is my search_results.ts:
import {Component} from '#angular/core';
import {NavController, NavParams} from 'ionic-angular';
import {Http} from '#angular/http';
import 'rxjs/add/operator/map';
#Component({
selector: 'page-page1',
templateUrl: 'search_results.html' })
export class SearchResults {
public term: any;
public ads: any;
public tmp: any;
constructor(public navCtrl: NavController, public params: NavParams, public http: Http) {
this.term = this.params.get('term');
this.ads = [];
this.tmp = [];
console.log("this.term", this.term);
this.http.get('http://www.truckers.host/app/search-ads.php')
.map(res => res.json()).subscribe(data => {
console.log("this is returned from http.get", data);
});
}
ngOnInit() {
// Let's navigate from TabsPage to Page1
console.log(this.params);
} }
Now, in my search_results.html to display the search results, I am not getting anything to print.
Here is that code:
<ion-header>
<ion-navbar>
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>
<img src="assets/images/trucker-to-trucker-logo.png" />
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding class="card-background-page">
<ion-card>
<ion-card-header>
Search Results
</ion-card-header>
<ion-card-content>
Searching for: <b>{{ term }}</b>
</ion-card-content>
</ion-card>
<ion-card>
<ion-list>
<ion-item *ngFor="let ad of ads">
{{ ad.ad_id }}
</ion-item>
</ion-list>
</ion-card>
</ion-content>
Nothing is returned, or iterated over.
When I console.log(data), I get an Object of Objects, and Ionic does not want to loop them.
Please let me know what other information I should include to help.
*ngFor only supports for Array and not Json Object.
You should consider using a custom Pipe to convert Object to Array.
Documentation about Pipe.
#Pipe({name: 'toArray'})
export class ToArrayPipe implements PipeTransform {
transform(inputObj: any, arg: any) {
if (!inputObj) { return [] }
let arr = [];
for(let key in inputObj) {
// Option1 (only value without the json object's key)
// this way will lose the key of Json Object
//arr.push(inputObj[key]);
// OPtion2 (both the key and value)
let obj = {};
obj[key] = inputObj[key];
arr.push(obj);
}
return arr;
}
}
Then add it to declarations of NgModule, and use it in your temple this way:
<ion-item *ngFor="let ad of ads | ToArray">
...
</ion-item>

Filter JSON by specific value ionic 2

im new in IOnic 2 and Angular, i try to filter a Json to show only a especific value; example get only user by gender. this is my code
home.html
<ion-list>
<ion-item *ngFor="let item of items | filter: {item.gender:'female'}" (click)="itemClicked($event,item)">
<ion-avatar item-left>
<img src="{{item.picture.thumbnail}}">
</ion-avatar>
<h2>{{item.name.first | uppercase }}</h2>
<h3>{{item.name.last | uppercase }}</h2>
<p>{{item.gender}}</p>
<button ion-button item-right color="danger" (click)="buttonClick($event)">Button</button>
</ion-item>
</ion-list>
This is my .ts file with the API Service
import { Component } from '#angular/core';
import {Http} from '#angular/http';
import { NavController } from 'ionic-angular';
import 'rxjs/add/operator/toPromise';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
public items:any;
constructor(public navCtrl: NavController,public http: Http) {
this.http = http;
this.http.get("http://api.randomuser.me/?results=10")
.subscribe(data =>{
//console.log(data['_body']);
this.items=JSON.parse(data['_body']).results;//Bind data to items object
},error=>{
console.log(error);// Error getting the data
} );
}
buttonClick(event){
console.log("button clicked");
console.log(event);
}
itemClicked(event,itemData){
console.log("item clicked");
console.log(event);
console.log(itemData);
}
}
But my idea does not work
any idea to help me-?? :`/
You can do that in the component code instead of in the view...
import { Component } from '#angular/core';
import {Http} from '#angular/http';
import { NavController } from 'ionic-angular';
import 'rxjs/add/operator/toPromise';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
public items: any;
constructor(public navCtrl: NavController, public http: Http) {
// this.http = http; <- You don't need this, this.http is already available because by declaring it in the constructor, now a public property is created in the component
this.http.get("http://api.randomuser.me/?results=10")
.map(data => data.json().results) // Instead of getting the _body manually, you can use the map method from RxJS
.subscribe(data =>{
//console.log(data);
this.items = data.filter(item => item.gender === 'female');
},error=>{
console.log(error);// Error getting the data
});
}
// ...
}
And now in your view
<ion-list>
<ion-item *ngFor="let item of items" (click)="itemClicked($event,item)">
<ion-avatar item-left>
<img src="{{ item.picture.thumbnail }}">
</ion-avatar>
<h2>{{ item.name.first | uppercase }}</h2>
<h3>{{ item.name.last | uppercase }}</h2>
<p>{{ item.gender }}</p>
<button ion-button item-right color="danger" (click)="buttonClick($event)">Button</button>
</ion-item>
</ion-list>

User data not showing on Html page in Ionic 2 and Firebase 3

I am using a project to get some user data from Firebase. I want to put that data into a "Profile page". Everything works except for one problem. The data doesn't show on the html page until I click on an item in the page, like to edit some data for example. The data will also show if I click back, then reenter the page. So it's like the data loads the blank template, but never updates it once the data from Facebook is received. Any suggestions? Here is some of the code from the page.
profile.html
<ion-header>
<ion-navbar color="primary">
<ion-title>Profile</ion-title>
<ion-buttons end>
<button ion-button item-left icon-right (click)="logOut()">
<ion-icon name=""></ion-icon>
Logout
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-list>
<ion-list-header>
Personal Information
</ion-list-header>
<ion-item (click)="updateName()">
<ion-grid>
<ion-row>
<ion-col width-50>
Name
</ion-col>
<ion-col *ngIf="userProfile?.firstName || userProfile?.lastName">
{{userProfile?.firstName}} {{userProfile?.lastName}}
</ion-col>
<ion-col class="placeholder-profile" *ngIf="!userProfile?.firstName">
<span>
Tap here to edit.
</span>
</ion-col>
</ion-row>
</ion-grid>
</ion-item>
<ion-item>
<ion-label class="dob-label">Date of Birth</ion-label>
<ion-datetime displayFormat="MMM D, YYYY" pickerFormat="D MMM YYYY"
[(ngModel)]="birthDate" (ionChange)="updateDOB(birthDate)"></ion-datetime>
</ion-item>
<ion-item (click)="updateEmail()">
<ion-grid>
<ion-row>
<ion-col width-50>
Email
</ion-col>
<ion-col width-50 *ngIf="userProfile?.email">
{{userProfile?.email}}
</ion-col>
<ion-col class="placeholder-profile" *ngIf="!userProfile?.email">
<span>
Tap here to edit.
</span>
</ion-col>
</ion-row>
</ion-grid>
</ion-item>
<ion-item (click)="updatePassword()">
<ion-grid>
<ion-row>
<ion-col width-50>
Password
</ion-col>
<ion-col class="placeholder-profile">
<span>
Tap here to edit.
</span>
</ion-col>
</ion-row>
</ion-grid>
</ion-item>
</ion-list>
</ion-content>
Here is the code from the profile.ts page
import { NavController, AlertController } from 'ionic-angular';
import { Component } from '#angular/core';
import { ProfileData } from '../../providers/profile-data';
import { AuthData } from '../../providers/auth-data';
import { LoginPage } from '../login/login';
#Component({
selector: 'page-profile',
templateUrl: 'profile.html',
})
export class ProfilePage {
public userProfile: any;
public birthDate: string;
zone: NgZone;
constructor(public navCtrl: NavController, public profileData: ProfileData,
public authData: AuthData, public alertCtrl: AlertController) {
}
ionViewDidEnter(){
this.profileData.getUserProfile().on('value', (data) => {
this.userProfile = data.val();
this.birthDate = this.userProfile.birthDate;
});
}
I also tried wrapping it in an NgZone object as suggested by others, which looks like this:
import { NavController, AlertController } from 'ionic-angular';
import { Component } from '#angular/core';
import { ProfileData } from '../../providers/profile-data';
import { AuthData } from '../../providers/auth-data';
import { LoginPage } from '../login/login';
import { NgZone } from '#angular/core';
#Component({
selector: 'page-profile',
templateUrl: 'profile.html',
})
export class ProfilePage {
public userProfile: any;
public birthDate: string;
zone: NgZone;
constructor(public navCtrl: NavController, public profileData: ProfileData,
public authData: AuthData, public alertCtrl: AlertController) {
this.zone = new NgZone({});
this.zone.run(() => {
//Your promise code
this.profileData.getUserProfile().on('value', (data) => {
this.userProfile = data.val();
this.birthDate = this.userProfile.birthDate;
});
});
}
None of this seems to work. The data is there, it just doesn't show until I click on an item/UI object, then it populates correctly. Help!
You have to do it like below.Hope code is self-explanatory.If you have any question, please comment below.
How to install Angularfire2?
ProfileData.ts
import { AngularFire, FirebaseListObservable, FirebaseObjectObservable } from 'angularfire2';
#Injectable()
export class ProfileData {
constructor(public af: AngularFire) {}
getUserProfile(data: string): FirebaseObjectObservable<any> {
return this.af.database.object(`path-to-your-firebase-object`);
}
}
YourComponent.ts
public profile: any;
constructor(public profileData: ProfileData) {
this.profileData.getUserProfile(your-user-id).subscribe(profileSnap => {
this.profile= profileSnap ;
});
}