Call function in app.component from page.ts [IONIC4] - ionic-framework

If I have a function in:
results.ts
export class ResultsPage implements OnInit {
myFunc() {
alert('my function works!');
}
}
app.component.html
<button (click)="myFunc()">CALL</button>
can I call this function in my app.component.html?

You should use angular providers and services
run ionic g service SomeProvider
inside SomeProvider create your function
import { Injectable } from '#angular/core';
#Injectable()
export class SomeProvider {
constructor() {
}
someFunction(){
console.log("I do something useful!");
}
}
set up as a provider in the app.module.ts file:
#NgModule({
declarations: [
MyApp
],
imports: [
BrowserModule,
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp
],
providers: [
SomeProvider // <-- List providers here
]
})
export class AppModule { }
inject into classes that want to use them:
import { Component } from '#angular/core';
import { IonicPage } from 'ionic-angular';
import { SomeProvider } from '../../providers/some-provider/some-provider';
#IonicPage()
#Component({
selector: 'page-something',
templateUrl: 'something.html',
})
export class SomePage {
constructor(public myService: SomeService) {
}
ionViewDidLoad() {
this.myService.someFunction(); // This will log "I do something useful!"
}
}
Here you can find complete guide: https://www.joshmorony.com/when-to-use-providersservicesinjectables-in-ionic/

Related

Deeplinks with Ionic / Capacitor

I'm trying to retrieve a request param from a deeplink to a Ionic 5 application using Deeplink plugin (authorization code provided by authorization server on successful authorization redirection).
Android intent filter seems correctly configured as the app is opening after successful authentication.
I keep having unmatched deeplinks with plugin_not_installed error.
app.module.ts:
import { HttpClientModule } from '#angular/common/http';
import { APP_INITIALIZER, NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { RouteReuseStrategy } from '#angular/router';
import { Deeplinks } from '#ionic-native/deeplinks/ngx';
import { SQLitePorter } from '#ionic-native/sqlite-porter/ngx';
import { SQLite } from '#ionic-native/sqlite/ngx';
import { Vibration } from '#ionic-native/vibration/ngx';
import { IonicModule, IonicRouteStrategy } from '#ionic/angular';
import { IonicStorageModule } from '#ionic/storage';
import { ApiModule as NumeraApiModule } from '#lexi-clients/numera';
import { OidcUaaModule } from '#lexi/oidc-uaa';
import { AuthModule, OidcConfigService } from 'angular-auth-oidc-client';
import { environment } from '../environments/environment';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { SettingsService } from './settings/settings.service';
export function loadSettings(config: SettingsService) {
return () => config.load();
}
export function configureAuth(oidcConfigService: OidcConfigService) {
return () => oidcConfigService.withConfig(environment.authentication.angularAuthOidcClient);
}
#NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [
AuthModule.forRoot(),
BrowserModule,
HttpClientModule,
IonicModule.forRoot(),
IonicStorageModule.forRoot(),
NumeraApiModule,
OidcUaaModule,
AppRoutingModule,
],
providers: [
{
provide: APP_INITIALIZER,
useFactory: loadSettings,
deps: [SettingsService],
multi: true,
},
{
provide: APP_INITIALIZER,
useFactory: configureAuth,
deps: [OidcConfigService],
multi: true,
},
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
Deeplinks,
OidcConfigService,
SQLite,
SQLitePorter,
Vibration,
],
bootstrap: [AppComponent],
})
export class AppModule {}
app.component.ts:
import { AfterViewInit, Component, NgZone, OnDestroy, OnInit } from '#angular/core';
import { NavigationEnd, Router } from '#angular/router';
import { App, Plugins, StatusBarStyle } from '#capacitor/core';
import { AppCenterCrashes } from '#ionic-native/app-center-crashes';
import { Deeplinks } from '#ionic-native/deeplinks/ngx';
import { NavController, Platform } from '#ionic/angular';
import { LexiUser, UaaService } from '#lexi/oidc-uaa';
import { Observable, Subscription } from 'rxjs';
import { SettingsPage } from './settings/settings.page';
import { SettingsService } from './settings/settings.service';
#Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.scss'],
})
export class AppComponent implements AfterViewInit, OnInit, OnDestroy {
constructor(
private platform: Platform,
private router: Router,
private idService: UaaService,
private settings: SettingsService,
private navController: NavController,
private deeplinks: Deeplinks,
private zone: NgZone
) {
this.platform.ready().then(async () => {
if (this.platform.is('mobile')) {
const { SplashScreen, StatusBar } = Plugins;
StatusBar.setStyle({ style: StatusBarStyle.Light });
SplashScreen.hide();
}
});
}
ngAfterViewInit() {
if (this.platform.is('mobile')) {
this.deeplinks.routeWithNavController(this.navController, { 'login-callback': SettingsPage }).subscribe(
(match) => {
console.log('Successfully matched route', match);
// Create our internal Router path by hand
const internalPath = '/settings';
// Run the navigation in the Angular zone
this.zone.run(() => {
this.router.navigateByUrl(internalPath);
});
},
(nomatch) => {
// nomatch.$link - the full link data
console.error("Got a deeplink that didn't match", nomatch);
}
);
}
}
}
I got it. My Ionic project is a module in an Angular multi-module project and plugin npm dependencies where added to root package.json.
Moving all Ionic-native related dependencies to package.json in Ionic project folder and running ionic cap sync again solved my problem.
Now the question is How to properly configure a Ionic module in an Angular mono-repo (aka multi-module project)?

two Listviews inside tabview don't work as expected

I have a code sharing Nativescript-Angular project. I am using two ListView's in a Lazy loaded module. The lazy loaded module is structured such that when I navigate to that module from AppModule.
<TabView id="tabViewContainer">
<page-router-outlet actionBarVisibility="never" *tabItem="{title: 'Players'}" name="playersTab"></page-router-outlet>
<page-router-outlet actionBarVisibility="never" *tabItem="{title: 'Event Requests'}" name="eventRequestsTab"></page-router-outlet>
</TabView>
Now each tab item is a page-router-outlet which routes to a child component and that child
component has ListView as parent element as shown below.
<ListView
class="list-group"
[items]="players"
(loaded)="onListViewLoaded($event)"
#listView
>
<ng-template let-player="item" let-third="third">
<GridLayout class="list-group-item" rows="*" columns="auto, *">
<Image
col="0"
[src]="player.photoURL"
class="thumb img-circle"
></Image>
<StackLayout col="1">
<Label
[text]="player.displayName"
class="list-group-item-heading"
></Label>
<Label
[text]="player.uid"
class="list-group-item-text"
textWrap="true"
></Label>
</StackLayout>
</GridLayout>
</ng-template>
</ListView>
Now the problem I am facing is when these two list views are shown side by side sometimes both the list views don't show anything and sometimes only the second tab shows data where as the first tab only shows the item dividers as shown below:-
Case 1 tab-1
Case 1 tab-2
Case 2 tab-1
Case 2 tab-2
The items always have more than one element but still this problem is being arised.
I have tried using the function listview.refresh() but still no success with that. I have also used ChangedDetectionStratergy.OnPush and called markedForRefresh function when data is received. I have tried using ObservableArray provided by Nativescript but I was bit confused while using that and also I felt it was not available for code sharing project.
I am frustrated since yesterday and it looks like a bug in Nativescript. Can you help overcome it so that both tabs shows the data always(knowing the arrays always have atleast one element) ?
Two listview is working inside tabView for example:-
app.component.html :-
`<TabView androidTabsPosition="bottom">
<page-router-outlet *tabItem="{title: 'Home', iconSource: getIconSource('home')}"
name="homeTab">
</page-router-outlet>
<page-router-outlet *tabItem="{title: 'Browse', iconSource: getIconSource('browse')}"
name="browseTab">
</page-router-outlet>
</TabView>`
app.component.ts:-
`import { Component, OnInit } from "#angular/core";
import { isAndroid } from "tns-core-modules/platform";
#Component({
selector: "ns-app",
moduleId: module.id,
templateUrl: "app.component.html"
})
export class AppComponent implements OnInit {
constructor() {
// Use the component constructor to inject providers.
}
ngOnInit(): void {
// Init your component properties here.
}
getIconSource(icon: string): string {
const iconPrefix = isAndroid ? "res://" : "res://tabIcons/";
return iconPrefix + icon;
}
}
`
app.module.ts :-
`import { NgModule, NO_ERRORS_SCHEMA } from "#angular/core";
import { NativeScriptModule } from "nativescript-angular/nativescript.module";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
#NgModule({
bootstrap: [
AppComponent
],
imports: [
NativeScriptModule,
AppRoutingModule
],
declarations: [
AppComponent
],
schemas: [
NO_ERRORS_SCHEMA
]
})
export class AppModule { }
`
app.routing.ts :-
`import { NgModule } from "#angular/core";
import { Routes } from "#angular/router";
import { NSEmptyOutletComponent } from "nativescript-angular";
import { NativeScriptRouterModule } from "nativescript-angular/router";
const routes: Routes = [
{
path: "",
redirectTo: "/(homeTab:home/default//browseTab:browse/default)",
pathMatch: "full"
},
{
path: "home",
component: NSEmptyOutletComponent,
loadChildren: "~/app/home/home.module#HomeModule",
outlet: "homeTab"
},
{
path: "browse",
component: NSEmptyOutletComponent,
loadChildren: "~/app/browse/browse.module#BrowseModule",
outlet: "browseTab"
}
];
#NgModule({
imports: [NativeScriptRouterModule.forRoot(routes)],
exports: [NativeScriptRouterModule]
})
export class AppRoutingModule { }
`
home.component.html :-
`<GridLayout class="page page-content">
<ListView [items]="items" class="list-group">
<ng-template let-item="item">
<ScrollView height="150">
<Label [text]="item.name" class="list-group-item"></Label>
</ScrollView>
</ng-template>
</ListView>
</GridLayout>`
home.component.ts:-
`import { Component, OnInit } from "#angular/core";
import { DataService, IDataItem } from "../shared/data.service";
#Component({
selector: "Home",
moduleId: module.id,
templateUrl: "./home.component.html"
})
export class HomeComponent implements OnInit {
items: Array<IDataItem>;
constructor(private _itemService: DataService) { }
ngOnInit(): void {
this.items = this._itemService.getItems();
}
}`
home.module.ts:-
`import { NgModule, NO_ERRORS_SCHEMA } from "#angular/core";
import { NativeScriptCommonModule } from "nativescript-angular/common";
import { HomeRoutingModule } from "./home-routing.module";
import { HomeComponent } from "./home.component";
import { ItemDetailComponent } from "./item-detail/item-detail.component";
#NgModule({
imports: [
NativeScriptCommonModule,
HomeRoutingModule
],
declarations: [
HomeComponent,
ItemDetailComponent
],
schemas: [
NO_ERRORS_SCHEMA
]
})
export class HomeModule { }`
home-routing.module.ts:-
`import { NgModule } from "#angular/core";
import { Routes } from "#angular/router";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { HomeComponent } from "./home.component";
import { ItemDetailComponent } from "./item-detail/item-detail.component";
const routes: Routes = [
{ path: "default", component: HomeComponent },
{ path: "item/:id", component: ItemDetailComponent }
];
#NgModule({
imports: [NativeScriptRouterModule.forChild(routes)],
exports: [NativeScriptRouterModule]
})
export class HomeRoutingModule { }`
browse.component.html :-
`<GridLayout class="page page-content">
<ListView [items]="items" class="list-group">
<ng-template let-item="item">
<ScrollView height="150">
<Label [text]="item.name" class="list-group-item"></Label>
</ScrollView>
</ng-template>
</ListView>
</GridLayout>`
browse.component.ts:-
`import { Component, OnInit } from "#angular/core";
import { DataService, IDataItem } from "../shared/data.service";
#Component({
selector: "Browse",
moduleId: module.id,
templateUrl: "./browse.component.html"
})
export class BrowseComponent implements OnInit {
items: Array<IDataItem>;
constructor(private _itemService: DataService) { }
ngOnInit(): void {
this.items = this._itemService.getItems();
}
}
`
browse.module.ts:-
`import { NgModule, NO_ERRORS_SCHEMA } from "#angular/core";
import { NativeScriptCommonModule } from "nativescript-angular/common";
import { BrowseRoutingModule } from "./browse-routing.module";
import { BrowseComponent } from "./browse.component";
import { DataService } from "../shared/data.service";
#NgModule({
imports: [
NativeScriptCommonModule,
BrowseRoutingModule
],
declarations: [
BrowseComponent
],
schemas: [
NO_ERRORS_SCHEMA
],
providers:[
DataService
]
})
export class BrowseModule { }`
browse-routing.module.ts:-
`import { NgModule } from "#angular/core";
import { Routes } from "#angular/router";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { BrowseComponent } from "./browse.component";
const routes: Routes = [
{ path: "default", component: BrowseComponent }
];
#NgModule({
imports: [NativeScriptRouterModule.forChild(routes)],
exports: [NativeScriptRouterModule]
})
export class BrowseRoutingModule { }
`
Example Available On Here:-
Nativescript playground url

Adding new components with default layout

I have just downloaded the angular admin template. Then i add a new component:
ng g n test
When I navigate to the component, the default layout is not applied. I guess it uses the app.component layout. How do you tell the component it should use the default UI?
to add a new componet follow these steps:
create a component-name-routing.module.ts file
create a component-name.module.ts file
create a component-name.component.html file
create a component-name.component.ts file
component-name.component.ts file:
import { Component, OnInit, Input } from "#angular/core";
#Component({
selector: 'app-componentName',
templateUrl: './component-name.component.html',
})
export class NameComponent implements OnInit {}
component-name-routing.module.ts file
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { NameComponent } from "./component-name.component";
const routes: Routes = [
{
path: '',
component: NameComponent,
data: {
title: 'route title'
},
children: [
{
path: '',
redirectTo: ''
},
]
}
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ComponentNameRoutingModule {}
component-name.module.ts file
// Angular
import { CommonModule } from '#angular/common';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
// Theme Routing
import { ComponentNameRoutingModule } from "./component-name-routing.module";
import { ComponentNameComponent } from "./component-name.component";
#NgModule({
imports: [
ComponentNameRoutingModule,
],
declarations: [
ComponentNameComponent
]
})
export class ComponentNameModule {
constructor() {}
}
all this in a new folder in the views directory and you'll be good to go.

Import class into ionic 3 and error when instantiating class

I'm new to ionic 3 and I'm trying to register. I have a accounts screen called accounts.ts that gets in src/pages/accounts/accounts.ts and then I'm trying to create a class where DAO will be referring to that class, I created it in the following src/dao/dao-accounts.ts location.
Some errors are showing up
My first doubt is this, do you mind this current?
import {DAOContas} from '../../dao/da-contacts';
I am also wanting to return a list of data but an error appears like this
:
uncaught (im promisse): referrererror: value is not defined
referenceerror: value is not defined at new ContasPage
class dao-accounts.ts
export class DAOContas {
constructor()
{
this.list = [];
}
getList()
{
this.list = [
{descricao:"Alimentação"},
{descricao:"Lazer"},
{descricao:"Transporte"}
];
return this.list;
}
}
method ContasPage.ts
import { Component } from '#angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { DAOContas } from '../../dao/dao-contas';
#Component({
selector: 'page-list',
templateUrl: 'contas.html'
})
export class ContasPage {
constructor(public navCtrl: NavController, public navParams: NavParams) {
this.dao = new DAOContas();
this.listcontas = this.dao.getList();
}
}
Error Occurs When Instantiating DAOContas
So the issue here relates to dependency injection pattern. See official documentation of how that works for more info.
Based on the code you provided it seems like the issue is with the way you organized your code and declared (or did not declare) certain variables.
In your ContasPage do ensure you:
import the class
declare the vars
do assignments in the constructor
So in your case you didn't declare the vars before the constructor:
import { Component } from '#angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { DAOContas } from '../../dao/dao-contas';
#Component({
selector: 'page-list',
templateUrl: 'contas.html'
})
export class ContasPage {
// declare your vars here:
dao: any;
listcontas: any;
constructor(
public navCtrl: NavController
) {
this.dao = new DAOContas();
this.listcontas = this.dao.getList();
}
}
Same thing in your class you forgot to declare the var list:
export class DAOContas {
list: Array<{ descricao: string }>
constructor() {
this.list = [];
}
getList() {
this.list = [
{ descricao: "Alimentação" },
{ descricao: "Lazer" },
{ descricao: "Transporte" }
];
return this.list;
}
}
Also since your DAOContas to me looks like a data provider, I would probably think about turning it into a provider and injecting it into your page via constructor:
Make sure DAOContas is injectable:
import { Injectable } from '#angular/core'
#Injectable()
export class DAOContas {
list: Array<{ descricao: string }>
constructor() {
this.list = [];
}
getList() {
this.list = [
{ descricao: "Alimentação" },
{ descricao: "Lazer" },
{ descricao: "Transporte" }
];
return this.list;
}
}
Add it to your app.module.ts as provider:
import { DAOContas } from '../../src/providers/dao-contacts';
#NgModule({
declarations: [
bla
],
imports: [
BrowserModule,
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp
],
providers: [
DAOContas,
StatusBar,
SplashScreen,
{ provide: ErrorHandler, useClass: IonicErrorHandler },
TestProvider
]
})
export class AppModule { }
Finally inject it to your page:
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { DAOContas } from '../../providers/dao-contacts';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage2 {
listcontas: any;
constructor(
public navCtrl: NavController,
public dao: DAOContas
) {
this.listcontas = this.dao.getList();
console.log(this.listcontas)
}
}

No Component Factory found for AddDataPage

I am trying to learn ionic. This is my very first application. It gives me an error as such:
app.module.ts
import { AddDataPage } from './../pages/add-data/add-data';
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 { SQLite } from '#ionic-native/sqlite';
import { Toast } from '#ionic-native/toast';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
#NgModule({
declarations: [
MyApp,
HomePage
],
imports: [
BrowserModule,
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage
],
providers: [
StatusBar,
SplashScreen,
{provide: ErrorHandler, useClass: IonicErrorHandler},
SQLite,
Toast
]
})
export class AppModule {}
add-data.ts
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { SQLite, SQLiteObject } from '#ionic-native/sqlite';
import { Toast } from '#ionic-native/toast';
/**
* Generated class for the AddDataPage page.
*
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-add-data',
templateUrl: 'add-data.html',
})
export class AddDataPage {
data = { date:"", type:"", description:"", amount:0 };
constructor(public navCtrl: NavController,
public navParams: NavParams,
private sqlite: SQLite,
private toast: Toast) {}
saveData() {
this.sqlite.create({
name: 'ionicdb.db',
location: 'default'
}).then((db: SQLiteObject) => {
db.executeSql('INSERT INTO expense VALUES(NULL,?,?,?,?)',[this.data.date,this.data.type,this.data.description,this.data.amount])
.then(res => {
console.log(res);
this.toast.show('Data saved', '5000', 'center').subscribe(
toast => {
this.navCtrl.popToRoot();
}
);
})
.catch(e => {
console.log(e);
this.toast.show(e, '5000', 'center').subscribe(
toast => {
console.log(toast);
}
);
});
}).catch(e => {
console.log(e);
this.toast.show(e, '5000', 'center').subscribe(
toast => {
console.log(toast);
}
);
});
}
ionViewDidLoad() {
console.log('ionViewDidLoad AddDataPage');
}
}
I really would like to learn this framework but most of the tutorials I see in youtube are for ionic 2. It is harder to learn if the ionic version I am downloading is different from what I am seeing in the tutorial. Specially if you are very new. Hope you can help. Thank you.
As the error is very clear that you have to add every page you create and use in ionic( if you are not using lazy loading) inside the declarations and also inside the entry components so just add your page AddDataPage in declarations and entry components section
In your app.module.ts inside #ngModule:
declarations: [
MyApp,
HomePage,
AddDataPage
],
And inside entryComponents
entryComponents: [
MyApp,
HomePage,
AddDataPage
]