This error seems to be a plague haunting Ionic 2. I've looked at several questions on this topic but none have been of help so far.
I've created this component Layout Component which wraps all my pages:
<ion-header>
<ion-navbar>
<button ion-button icon-only menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>
{{pageName}}
</ion-title>
</ion-navbar>
</ion-header>
<ng-content>
</ng-content>
<ion-footer>
<ion-toolbar>
<ion-tabs>
<ion-tab [root]="usersPage" tabTitle="Chat" tabIcon="chat"></ion-tab>
</ion-tabs>
</ion-toolbar>
</ion-footer>
and the TS File looks like so:
export class AstootLayoutComponent {
#Input() pageName: string;
usersPage: any = UsersPage;
profilePage: any = ProfilePage;
}
Then I have a users page which consumes this component which looks like so:
<astoot-layout [pageName]="pageName">
<ion-content padding>
<page-list-base [detailPageType]="userDetailType" [baseProvider]="baseProvider" [config]="pageListConfiguration"></page-list-base>
</ion-content>
</astoot-layout>
When I attempt to start my application I receive an error:
Maximum call stack size exceeded
TypeError: Cannot read property 'getList' of undefined
at PageListBaseComponent.set [as baseProvider] (http://localhost:8100/build/main.js:115817:21)
at Wrapper_PageListBaseComponent.check_baseProvider (/AppModule/PageListBaseComponent/wrapper.ngfactory.js:38:31)
at CompiledTemplate.proxyViewClass.View_UsersPage0.detectChangesInternal (/AppModule/UsersPage/component.ngfactory.js:80:35)
at CompiledTemplate.proxyViewClass.AppView.detectChanges (http://localhost:8100/build/main.js:111909:14)
at CompiledTemplate.proxyViewClass.DebugAppView.detectChanges (http://localhost:8100/build/main.js:112104:44)
at CompiledTemplate.proxyViewClass.AppView.internalDetectChanges (http://localhost:8100/build/main.js:111894:18)
at CompiledTemplate.proxyViewClass.View_UsersPage_Host0.detectChangesInternal (/AppModule/UsersPage/host.ngfactory.js:29:19)
at CompiledTemplate.proxyViewClass.AppView.detectChanges (http://localhost:8100/build/main.js:111909:14)
at CompiledTemplate.proxyViewClass.DebugAppView.detectChanges (http://localhost:8100/build/main.js:112104:44)
at ViewRef_.detectChanges (http://localhost:8100/build/main.js:77367:20)
at NavControllerBase._viewAttachToDOM (http://localhost:8100/build/main.js:43575:40)
at NavControllerBase._transitionInit (http://localhost:8100/build/main.js:43678:18)
at NavControllerBase._postViewInit (http://localhost:8100/build/main.js:43531:14)
at NavControllerBase._viewTest (http://localhost:8100/build/main.js:43627:25)
at NavControllerBase._nextTrns (http://localhost:8100/build/main.js:43370:25)
Through some investigation the cause seems to be the fact that the AstootLayoutComponent references the Users page, where it resides in. Some how the creates a forever loop.
Why is this happening, the documentation doesn't seem to mention that you can't next this component on the page. How can I fix this?
Bounty Edit
I've created a Repository which replicates my issue
Just as a warning since the tabs controller is in a forever loop, and the api is pointed to github, so you may want to switch that before hitting there rate limit, you can change the url in the Environments.ts
I think you need to add a Tabs Component. Therefore some of the work you were doing in the astoot layout gets moved to this Tabs Component. I opened a PR: https://github.com/granthoff1107/Ionic-Sample-Max-Exceed/pull/1
I tested this and no more stack errors since you no longer have the recursive relationship between the astoot layout and the ion-tabs.
Remove the tabs component from the Astoot Layout Component:
<ion-header>
<ion-navbar>
<button ion-button icon-only menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>
{{pageName}}
</ion-title>
</ion-navbar>
</ion-header>
<ng-content>
</ng-content>
Create a seperate Tabs Component:
<ion-tabs>
<ion-tab [root]="usersPage" tabTitle="Chat" tabIcon="chat"></ion-tab>
<ion-tab [root]="profilePage" tabTitle="Profile" tabIcon="person"></ion-tab>
</ion-tabs>
With a type script file that contains the pages from the astoot layout component.
import { ProfilePage } from './../profile/profile';
import { UsersPage } from './../users/users';
import { Component } from '#angular/core';
#Component({
templateUrl: 'tabs.html'
})
export class TabsPage {
usersPage: any = UsersPage;
profilePage: any = ProfilePage;
constructor() {
}
}
Add your new tabs page the app.module.ts and set your rootPage: any = TabsPage; this will now act as your master page and your content will be transcluded into your view.
Related
I have just updated my app to ionic 5 and angular 9. I was hoping that this problem will disappear with the new version but it still persists. The issue is that in my app all are pages transitioning with a black screen before the real page comes in. So the user would see for like some millisecond a black screen, what really does not look nicely. Now with the new version things got even worse. In some pages I also experience the black boxes in the ion-refresher area or when opening the keyboard. As well when opening the new modals(in some its working properly in some not) But with the modals the black background even stays behind the modal. I really have no idea why this is happening. I also don't know if code helps here because its actually the same in both modals or also for refreshing content. I have made two pictures of an correct working modal and one with the black background.
I appreciate any help and if you need further code, let me know!
further code:
working modal:
html:
<ion-header>
<ion-toolbar>
<ion-buttons slot="end">
<ion-button color="medium" (click)="dismiss()">
<ion-icon slot="icon-only" name="close"></ion-icon>
</ion-button>
</ion-buttons>
<ion-title color="medium">
Privacy Policy
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="legal-content">
<p> ... </p>
</ion-content>
ts:
async showPrivacyModal() {
const modal = await this.modalController.create({
component: PrivacyPolicyPage,
presentingElement: this.routerOutlet.nativeEl,
swipeToClose: true
});
return await modal.present();
}
buggy modal:
html:
<ion-header>
<ion-toolbar>
<ion-buttons slot="end">
<ion-button color="medium" (click)="dismiss()">
<ion-icon slot="icon-only" name="close"></ion-icon>
</ion-button>
</ion-buttons>
<ion-title color="medium">
Black BG
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
</ion-content>
ts:
async openFilter() {
const modal = await this.modalController.create({
component: FilterPage,
presentingElement: this.routerOutlet.nativeEl,
swipeToClose: true
});
return await modal.present();
}
Here the pictures:
I need to place the ion-refresher inside a component.
I have a list which is identical in look and behavior, my list component should have refresher, infinite-scroll etc in that one component
I try to add ion-refresher to a custom component.
<ion-refresher (ionRefresh)="refreshList($event)">
<ion-refresher-content></ion-refresher-content>
</ion-refresher>
but I get this error:
Parse Error: No provider for Content
Did u try?
<ion-content>
<ion-refresher (ionRefresh)="refreshList($event)">
<ion-refresher-content></ion-refresher-content>
</ion-refresher>
</ion-content>
As mentioned here and in the docs you need to put your refresher inside a <ion-content> tag.
<ion-content>
<ion-refresher (ionRefresh)="refreshList($event)">
<ion-refresher-content></ion-refresher-content>
</ion-refresher>
</ion-content>
when we place ion-refresher inside ion-content, it creates extra space
I have the problem that I tried to extract the headerbar into a own component but if I use this new component the content of the page goes behind the headerbar.
Without extracting the header and using the same code directly in the HTML it works correctly.
My new Component:
header-bar.component.ts
import { Component, Input } from '#angular/core';
#Component({
selector: 'my-header-bar',
templateUrl: 'header-bar.html'
})
export class MyHeaderBar {
#Input() pageTitle : String;
constructor() {}
}
header-bar.html
<ion-header>
<ion-navbar>
<button ion-button menuToggle icon-only>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>{{pageTitle}}</ion-title>
</ion-navbar>
</ion-header>
The page I try to use it:
home.html
<my-header-bar pageTitle="Einstellungen"> </my-header-bar>
<ion-content>
<h2>Welcome to Ionic!</h2>
<p>
This starter project comes with simple tabs-based layout for apps
that are going to primarily use a Tabbed UI.
</p>
...
</ion-content>
Why does it not work with my own component?
I'm using following code and have not faced any issue till now. I tried with following;
<ion-navbar navbar>
<ion-title >{{title}}</ion-title>
</ion-navbar>
Following is ts file code:
#Component({
selector: 'navbar',
templateUrl: 'navbar.html'
})
export class CommonNavbar {
public title: string;
constructor(
private nav: NavController) {
}
setTitle(title: string){
this.title = title;
console.log(this.title);
}
}
And using this in a following way:
<ion-header>
<navbar></navbar>
</ion-header>
I had also added some styling to common navbar( like centering the title) and configured this from the component/page by using following code snippet.
import { CommonNavbar } from '../../components/shared_nav/navbar';
#ViewChild(forwardRef(() => CommonNavbar)) commonNavbar: CommonNavbar;
ngAfterViewInit() {
this.commonNavbar.setTitle(title);
this.commonNavbar.centerTitle(true);
}
I tried to do the same in an older version of Ionic, and I was facing the same issues. I asked that on the Ionic Slack channel and #mhartington (from Ionic team) said:
There is no way to create a global ion-navbar, as this is done on
purpose. The point of having a navbar defined for each component is so
that we can properly animate the titles, navbar background color (if
you change them) and animate other properties needed.
And about creating a custom directive to avoid duplicating ion-header / ion-navbar html code:
That will still creat errors with how angular2 content projection
works. We have several issues that have been open when people try this
and the best answer is to not do it.
I am trying to add a variable containing html to my ionic 3 page
Ionic Page:
<ion-header>
<ion-navbar>
<ion-title>{{offeritem.data.nameprovider}}</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<div>
{{offeritem.data.detailsoffer}}
</div>
</ion-content>
However I am getting the following
Result:
<p>The table contains 30 pieces:</p><ul><li>5 Philadelphia Roll</li>
<li>5 Fantasia Roll</li>
Please let me know what I am doing wrong in this case.
Thanks in advance
You should use [innerHTML] for ionic 3 like this:
<p [innerHTML]="yourVarHere"></p>
<span [innerHTML]="offeritem.data.detailsoffer"></span>
REF
Note the section on "Property binding or interpolation?"
import {DomSanitizationService} from '#angular/platform-browser';
class....{
public getSafehtml(html:string){
return this.sanitizer.bypassSecurityTrustHtml(html);
}
}
<ion-content padding>
<div [innerHTML]="getSafehtml(offeritem.data.detailsoffer)"></div>
</ion-content>
If you not bypassSecurityTrustHtml then your style will not work.
I'm using Ionic 2 and trying to use getElementbyId on
<ion-content padding>
<ion-list id="list"></ion-list>
</ion-content>
so that i can add items the following way:
var listIon=document.getElementById("list");
var li = document.createElement("ion-item");
li.innerText=usern+": "+mensaje;
var p = document.createElement("p");
p.appendChild(li);
listIon.appendChild(p);
It works perfectly fine the first time, but if I exit the page and reopen it I get an error saying that
cannot read property appendChild on null
. I have already read other questions where they say that the script is not at the bottom. By taking in count that in Ionic you don't put the script in the html at all I don't know what could be causing this.
Edit
I have uploaded the files here main problem is in chat-details, chat-details is opened from chat.
What exactly are you trying to do? I think you're thinking in an old Jquery way, but Ionic works on top of Angular2, so things are done in a different way.
I assume you want to append a new item to a list, which can be done by using *ngFor and an array of data. Or if you want to show a message under certain conditions, you can accomplish that by using *ngIf. You should try to avoid referencing the DOM directly, and update the component code instead to change the data shown in the view.
I've created this demo plunker just to show you how to do these things in a Angular2 way. Please let me know what would be the expected result, so I can update the plunker accordingly.
Component code:
#Component({
selector: 'page-home',
templateUrl: 'app/home.page.html'
})
export class HomePage {
private count: number;
public users: Array<string>;
public showMessage: boolean;
public message: string;
constructor() {
this.count = 1;
this.users = [];
this.showMessage = false;
this.message = 'This is a secret message!';
}
public addUser(): void {
this.users.push(`User ${this.count++}`);
}
public toggleMessage(): void {
this.showMessage = !this.showMessage;
}
}
View code:
<ion-header>
<ion-navbar>
<ion-title>HomePage</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<h2>Users</h2>
<p *ngIf="showMessage">{{ message }}</p>
<ion-list *ngFor="let user of users">
<ion-item>
<p>{{ user }}</p>
</ion-item>
</ion-list>
<button ion-button (click)="addUser()">Add a user</button>
<button ion-button (click)="toggleMessage()">Togle message</button>
</ion-content>