Ionic TypeError: b is undefined - ionic2

I have an Ionic2 app, that has just stopped working (not sure why).
The following command:
ionic serve
Builds the app with no errors, but when http://localhost:8100/ is loaded into the browser, I get:
TypeError: b is undefined
In order to debug this I tried to put a console.log at the top of app.ts constructor, but this is not being printed.
Does anyone have any ideas what is wrong, or were I should look to try diagnose this?
Thanks
UPDATE
I have been doing some more debugging, and I have found that this is related to inheritance of a variable I think.
I have the following code:
search.ts
export class SearchPage extends SearchSubParentPage {
constructor(ref: ChangeDetectorRef, nav: NavController, private viewCtrl: ViewController, jobService: JobService, personService: PersonService, utilityService: UtilityService, navParams: NavParams, popoverController: PopoverController, events: Events, platform: Platform, alertCtrl: AlertController, loadingController: LoadingController) {
super(ref, nav, viewCtrl, jobService, personService, utilityService, navParams, popoverController, events, platform, alertCtrl, loadingController, false, 0);
}
searchSubParent.ts
export class SearchSubParentPage extends SearchParent {
private popoverController: PopoverController = null;
constructor(ref: ChangeDetectorRef, nav: NavController, viewCtrl: ViewController, jobService: JobService, personService: PersonService, utilityService: UtilityService, navParams: NavParams, popoverController: PopoverController, events: Events, platform: Platform, alertCtrl: AlertController, loadingController: LoadingController, favourite: boolean, jobType: number) {
this.popoverController = popoverController;
}
As you can see, the popoverController object is passed via the constructor to the parent SearchSubParentPage.
If I have the following line of code in SearchSubParentPage, I get the error:
this.popover = this.popoverController.create(SearchJobsPopOverPage, {...
If I comment it out, it works. So this suggests that there is something wrong with the way I pass popoverController to the parent (I have the same issue with the nav object too).
If I console.log either this.popoverController or this.nav, they appear to be fine (i.e. not undefined or null).

If I make the object public, it works, not sure why.
change:
private popoverController: PopoverController = null;
to:
public popoverController: PopoverController = null;

Related

How to use Ionic 2's config api?

I do not understand how to use the config api that is listed here:
https://ionicframework.com/docs/api/config/Config/
Particularly this example below:
config.set('ios', 'favoriteColor', 'green');
// from any page in your app:
config.get('favoriteColor'); // 'green' when iOS
What are my imports? Can I do this in the app.module.ts? Also, the documents read that if I don't say the platform then the variable is available on all platforms, what would the syntax look like then?
config.set(null, 'appName', 'App')? config.set('appName', 'App')?
My man from Ghana answered this:
imports: [
BrowserModule,
IonicModule.forRoot(MyApp,
{
mode: 'ios',
fav: 'red'
})
],
And then from anywhere else:
import { NavController, Config } from 'ionic-angular';
constructor(public navCtrl: NavController
, public config: Config
) {
this.temp = this.config.get('fav');
}

"__zone_symbol_currentTask":{"type":"microTask","state":"notScheduled","source":"Promise.then","zone":"angular","cancelFn":null,"runCount":0}}

I am getting this error
"__zone_symbol_currentTask":{"type":"microTask","state":"notScheduled","source":"Promise.then","zone":"angular","cancelFn":null,"runCount":0}}
while login facebook from my hybrid application. I have used
ng2-cordova-oauth
plugin to achieve facebook login. My code look like.
import { Component } from '#angular/core';
import {IonicPage, NavController, Platform} from 'ionic-angular';
import {OauthCordova} from '../../../node_modules/ng2-cordova-oauth/platform/cordova';
import {Facebook} from '../../../node_modules/ng2-cordova-oauth/core';
#IonicPage()
#Component({
selector: 'page-facebook',
templateUrl: 'facebook.html',
})
export class FacebookPage {
public oauth: OauthCordova;
private provider: Facebook;
public constructor(public navCtrl: NavController, private platform: Platform) {
this.oauth = new OauthCordova();
this.provider = new Facebook({
clientId: "1807864452579635",
appScope: ['id','story','picture','link','type','full_picture','message']
});
}
public login() {
this.platform.ready().then(() => {
this.oauth.logInVia(this.provider).then((success) => {
alert(JSON.stringify(success));
}, (error) => {
console.log(JSON.stringify(error));
});
});
}
}
I ran into this on a project I was working on too. The problem turned out to be that the ng2-cordova-oauth dependencies weren't installed. Specifically we had to run:
cordova plugin add cordova-plugin-inappbrowser
cordova plugin add cordova-plugin-whitelist
cordova prepare
You may also have to whitelist your site using the information found at https://github.com/apache/cordova-plugin-whitelist
Edit: You can't use ng2-cordova-oauth from the browser. You have to use a device or a simulator.
note that it is unlikely for anyone to see the original error in this code since it in part depends on external dependencies
You can use
JSON.stringify(error,Object.getOwnPropertyNames(e));
to get a clear description of the error you getting, because The __zone_symbol_currentTask is a property inserted into the Error object by Angular and JSON.stringify does not output the Error object's own properties (by default)
see also: Is it not possible to stringify an Error using JSON.stringify?

Ionic 2, Tab content gets rendered before method execution in main page is completed

I have a dashboard page. and this page has two tabs to show recent sales and recent inventory.
When user inters dashboard, loadDashboardItems method is called.
My dashboard.ts
import { Component } from '#angular/core';
import {NavController, NavParams, LoadingController } from 'ionic-angular';
import {Storagehelper} from '../../providers/storagehelper';
import { DashboardrecentsalesPage } from '../dashboardrecentsales/dashboardrecentsales';
import { DashboardrecentinventoryPage } from '../dashboardrecentinventory/dashboardrecentinventory';
import {Webservice} from '../../providers/webservice';
/**
* Generated class for the Dashboard page.
*
* See http://ionicframework.com/docs/components/#navigation for more info
* on Ionic pages and navigation.
*/
#Component({
selector: 'page-dashboard',
templateUrl: 'dashboard.html',
})
export class DashboardPage {
private recentSales;
private recentInventory;
private loading;
private ajaxRequest;
constructor(public navCtrl: NavController, public navParams: NavParams, private storagehelper: Storagehelper, public loadingCtrl: LoadingController, public webservice: Webservice) {
this.loadDashboardItems();
this.recentSales = DashboardrecentsalesPage; //This is the default tab in dashboard page
this.recentInventory = DashboardrecentinventoryPage;
}
ionViewWillLeave(){
if(this.loading) this.loading.dismiss().catch(() => {});
if(this.ajaxRequest!=undefined){
this.ajaxRequest.unsubscribe();
}
}
private loadDashboardItems(){
//HERE API REQUEST IS MADE AND data is saved to Localstorage
}
}
And default tab dashboardrecentsales.ts
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams, Tabs } from 'ionic-angular';
import {Storagehelper} from '../../providers/storagehelper';
/**
* Generated class for the Dashboardsummaryitems page.
*
* See http://ionicframework.com/docs/components/#navigation for more info
* on Ionic pages and navigation.
*/
#Component({
selector: 'page-dashboardrecentsales',
templateUrl: 'dashboardrecentsales.html',
})
export class DashboardrecentsalesPage {
private RecentItems;
constructor(public navCtrl: NavController, public navParams: NavParams, private storagehelper: Storagehelper) {
this.getDashboardItems();
}
getDashboardItems(){
this.RecentItems = this.storagehelper.getStorageItem("RecentItems");
//This RecentItems property is used to render view dashboardrecentsales
}
}
Here in dashboard.ts the API request is made and data are saved in LocalStorage
And 'dashboardrecentsales.ts' fetches data from local storage and renders view to show on tab.
PROBLEM
The problem I have is if user is accessing dashboard page for the first time, Even though data are saved in localstorage, the tab page doesn't get any data from localstorage.
It seems Tab is rendered before execution of loadDashboardItems method of dashboard page gets completed.
I tried putting
this.recentSales = DashboardrecentsalesPage; //This is the default tab in dashboard page
this.recentInventory = DashboardrecentinventoryPage;
inside loadDashboardItems method when everything is saved to localstorage, but no tab view was rendered at all.
Can anybody suggest what can I do in this scenario.
For your case, you can make use of ionViewDidLoad() to load your dashboard items. Try something like this,
ionViewDidLoad(){
this.loadDashboardItems();
}
check this documentation to know more about all the predefined NavController methods
Hope that helps!
Anyway I solved it using event.publish and event.subscribe. More info Here
The sample code from the link. I used this logic to refresh the contents.
import { Events } from 'ionic-angular';
// first page (publish an event when a user is created)
constructor(public events: Events) {}
createUser(user) {
console.log('User created!')
events.publish('user:created', user, Date.now());
}
// second page (listen for the user created event after function is called)
constructor(public events: Events) {
events.subscribe('user:created', (user, time) => {
// user and time are the same arguments passed in `events.publish(user, time)`
console.log('Welcome', user, 'at', time);
});
}

ionic 2 TypeError: self.context.doInfinite is not a function

I am trying to load more data from the server and i am getting error in a console
zone.js:260
Uncaught EXCEPTION: Error in build/pages/home/home.html:30:23
ORIGINAL EXCEPTION: TypeError: self.context.doInfinite is not a function
ORIGINAL STACKTRACE:
TypeError: self.context.doInfinite is not a function
at DebugAppView._View_HomePage0._handle_ionInfinite_25_0..
home.ts has the following codes
import {Component} from '#angular/core';
import {NavController} from 'ionic-angular';
import {Http} from '#angular/http';
import 'rxjs/add/operator/map';
import {JobService} from '../job/job';
import {JobPage} from '../services/JobService';
#Component({
templateUrl: 'build/pages/home/home.html',
providers:[JobService]
})
export class HomePage {
public posts:any = [];
private start:number=0;
constructor(private navCtrl: NavController, public peopleService:PeopleService) {
this.loadPeople();
}
loadPeople() {
return new Promise(resolve => {
this.peopleService.load(this.start)
.then(data => {
for(let kazitz of data) {
this.posts.push(kazitz);
}
resolve(true);
});
});
}
doInfinite(infiniteScroll) {
console.log('doInfinite, start is currently '+this.start);
this.start+=5;
this.loadPeople().then(()=>{
infiniteScroll.complete();
});
}
}
Now, error says doInfinite is not a function while it is a function you see above, i am getting this error while the app tries to load more data.. in home.html normal ionic 2 load more codes i took from ionic framework docs
<ion-infinite-scroll (ionInfinite)="doInfinite($event)">
<ion-infinite-scroll-content
loadingSpinner="bubbles"
loadingText="Loading more...">
</ion-infinite-scroll-content>
</ion-infinite-scroll>
Any help will be appreciated!
I had the same issue, and it only worked when i added this.doInfinite(); to the Constructor() like this:
Constructor(){
this.doInfinite();
}
I cannot guarantee it will work, and I apologise if it doesn't. I am honestly still perplexed by it. Good luck!

Problems with NavController when unit testing an Ionic 2 app

I'm having trouble unit testing with NavController.
I'm stuck at this error:
Cannot resolve all parameters for 'NavController'(?, ?, ?, ?, ?, ?, ?, ?). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'NavController' is decorated with Injectable.
I tried everything I found on the net, like using '#Inject', and nothing seems to work.
Here is the code:
Component
import {Page, MenuController, NavController} from 'ionic-angular';
import {SignupPage} from '../signup/signup';
#Page({
templateUrl: 'build/pages/welcome/welcome.html'
})
export class WelcomePage {
// Variables
constructor(private menu: MenuController, private nav: NavController) {
this.menu.enable(false);
}
goToSignupPage() {
this.nav.push(SignupPage)
}
}
Unit test
import {beforeEachProviders, it, describe, expect, inject} from '#angular/core/testing';
import {MenuController, NavController} from 'ionic-angular';
import {WelcomePage} from './welcome';
describe('WelcomePage', () => {
beforeEachProviders(() => [WelcomePage, MenuController, NavController]);
it('should have the menu disabled on instatiation', inject([WelcomePage], (welcomePage) => {
// Expectations
expect(welcomePage.menu.isEnabled()).toBeFalsy();
}));
});
Any idea whats wrong?
UPDATE:
Thanks for the replies, guys.
It really helped me to understand how to do it.
I didn't use sinon, but I was able to test if the push was called
using the spyOn from Jasmine.
For that, I did a subtle change to the provide part:
beforeEachProviders(() => [WelcomePage, MenuController,
{ provide: NavController, useValue: {push: NavController.prototype.push} }]);
(Probably it would be nice to serve the NavController.prototype directly to have access to all the other properties.)
And then tested like this:
it('should go to signup page when calling goToSignupPage()',
inject([WelcomePage], (welcomePage) => {
// Spies
spyOn(welcomePage.nav, 'push').and.stub();
// Call
welcomePage.goToSignupPage();
// Expectations
expect(welcomePage.nav.push).toHaveBeenCalledWith(SignupPage);
}));
Try this on your Unit Test class:
beforeEachProviders(() => [WelcomePage, MenuController, provide(NavController, { useValue: WelcomePage })]);
and then:
import {provide} from '#angular/core';
As GoldBones, the problem is that the NavController that has been imported is a class not a provider, so you need to define your own provider. The provide(...) syntax is deprecated, but the final code is pretty similar to the old syntax:
beforeEachProviders(() => [WelcomePage, MenuController, {provide: NavController, useValue: {} }]);
I've used an empty object above, but as WelcomePage uses the push method, you will need to stub this out with something like:
let stubNavController = {push: (page) => {}};
beforeEachProviders(() => [WelcomePage, MenuController, {provide: NavController, useValue: stubNavController }]);
Using a spying library like Sinon could be useful here if you want to test that the method was called.