Property 'x' is private and only accessible within class 'y' - javascript

I have this piece of code:
import { Component } from '#angular/core';
import { NavController, Loading, Alert } from 'ionic-angular';
#Component({
templateUrl: 'build/pages/search/search.html',
})
export class SearchPage {
constructor (....)
{
// code here
}
findItems()
{
let loading = Loading.create({
content: "Finding items..."
});
this.nav.present(loading);
// other stuff here
}
When I run ionic serve everything shows correctly but when I click a button which calls findItems() method I get this error:
Error TS2341: Property 'create' is private and only accessible within class 'Loading
An analogous errors appears if I do:
let alert = Alert.create({
title: 'Hello!',
});
In this case in my terminal appears following message:Error TS2341: Property 'create' is private and only accessible within class 'Alert'.
I'm working with Ionic2 version 2.0.0-beta.36

EDIT: This only applies to beta 11 and higher
This is because create is a private function of the class Loading, and therefore not callable outside of the Loading class.
The code example from Ionic's documentation shows a LoadingController class used to instantiate the Loading object with the desired options. I would start there.
import { LoadingController } from 'ionic-angular';
//...
constructor(private loadingController: LoadingController) {
}
findItems() {
let loading = this.loadingController.create({
content: "Finding items..."
duration: 3000
});
loading.present();
// other stuff here
}

It looks like the syntax for Alerts has changed. Here's the new syntax:
import { AlertController } from 'ionic-angular';
export class MyPage {
constructor(private alertController: AlertController){
}
showAlert() {
let alert = this.alertController.create({
title: 'New Friend!',
subTitle: 'Your friend, Obi wan Kenobi, just accepted your friend request!',
buttons: ['OK']
});
alert.present();
}
}

Related

Extracting data from model to variables

I'm new to typescript and angular and I was trying to fetch some data from firebase using angularfire2 and assign it to variables to use in some other functions later. I'm only familiar with javascript dot notation where I access members of the object using dot notation seems like it doesn't work with angular can somebody please help me with extracting data from the model to variables, please
I'm still having a hard time understanding Observable and subscribes too.
code
model
export class Reacts {
sad?: number;
happy?: number;
neutral?: number;
}
service
import { Injectable } from "#angular/core";
import {
AngularFirestore,
AngularFirestoreCollection,
AngularFirestoreDocument
} from "angularfire2/firestore";
import { Reacts } from "../models/reacts";
import { Observable } from "rxjs";
#Injectable({
providedIn: "root"
})
export class ReactService {
mapCollection: AngularFirestoreCollection<Reacts>;
reacts: Observable<Reacts[]>;
constructor(public afs: AngularFirestoreDocument) {
this.reacts = this.afs.collection("reacts").valueChanges();
}
getItems() {
return this.reacts;
}
}
component
import { Component, OnInit } from "#angular/core";
import { Reacts } from 'src/app/models/reacts';
import { ReactService } from 'src/app/services/react.service';
#Component({
selector: "app-reacts",
templateUrl: "./reacts.component.html",
styleUrls: ["./reacts.component.css"]
})
export class ReactsComponent implements OnInit {
react: Reacts[];
happy: number;
sad: number;
neutral:number;
constructor(private reactsService: ReactService ) {}
ngOnInit(): void {
this.reactsService.getItems().subscribe(reacts => {
this.react = reacts;
console.log(reacts); //this works print an array object of data from database
this.happy= reacts.happy// what i'm trying to achieve
});
}
}
Ok, I'll break it down for you. You are trying to access .happy but it is actually an array of React[]
ngOnInit(): void {
this.reactsService.getItems().subscribe((reacts:Reacts[]) => { // Note I have defined its model type
this.react = reacts;
console.log(reacts); //this works print an array object of data from database
//this.happy= reacts.happy // Now VS code will show you error itself
this.happy = reacts[0].happy;
});
}
The power of typscript comes as it is strongly typed language. If you'll make changes as below in service, the VS Code will itself explain you the error:
export class ReactService {
mapCollection: AngularFirestoreCollection<Reacts>;
reacts: Observable<Reacts[]>;
constructor(public afs: AngularFirestoreDocument) {
this.reacts = this.afs.collection("reacts").valueChanges();
}
getItems(): Observable<Reacts[]> { // added return type
return this.reacts;
}
}
Once I provide return type of getItems() , you dont even have to define type in .subscribe((reacts:Reacts[]) as I have done in your component.

Cannot read property 'next' of undefined using BehaviorSubject

I'm having this isue only when i deploy to android (didn't tried on iOS), if i run ionic serve to view if all is fine, console doesn't throw me any error and working fine!, but when i try it in android, i have the issue:
Cannot read property 'next' of undefined
ok, let's make a description, first of all, i'm using the integrated ionic starter template side_menu, i have made some style modifications, (but only that), so let's view each component needed to reproduce this issue:
app.component.html:
here i only put an ionDidClose event in the ion-menu element, (other things in the document are not neccesary at all):
<ion-menu class = "shorted_menu" (ionDidClose) = "setDisplayMenuInfo('basicInfo')">
<!--More code here...-->
</ion-menu>
in app.component.ts i have:
import { Component } from '#angular/core';
import { Platform } from '#ionic/angular';
import { SplashScreen } from '#ionic-native/splash-screen/ngx';
import { StatusBar } from '#ionic-native/status-bar/ngx';
import { enableProdMode } from '#angular/core';
import { MenuController } from '#ionic/angular';
import { Storage } from '#ionic/storage';
import { Router} from '#angular/router';
import { OneSignal } from '#ionic-native/onesignal/ngx';
import { AppPages } from '../global_modules/app_pages';
import { showInfo, setComponentBehaviorSubject } from '../global_modules/menu_functionality';
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
enableProdMode();
#Component({
selector: 'app-root',
templateUrl: 'app.component.html'
})
export class AppComponent {
public appPages;
public showInfo;
public currentDisplayMenu = 'basicInfo';
public behaviorSubject: BehaviorSubject<string>;
public behaviorSubjectObservable: Observable<any>;
public behaviorSubjectSubscription: Subscription;
public setComponentBehaviorSubject;
constructor(
private platform: Platform,
private splashScreen: SplashScreen,
private statusBar: StatusBar,
private oneSignal: OneSignal,
private storage: Storage,
private router: Router,
public menu: MenuController
)
{
this.initializeApp();
}
async setup(){
this.appPages = AppPages.pages;
this.showInfo = showInfo;
this.setComponentBehaviorSubject = setComponentBehaviorSubject;
this.userData = await this.getUserData();
this.userAvatar = this.userData.data.avatar_src.src && this.userData.data.avatar_src.src != "" ?
`${this.imagesRoute}${this.userData.data.avatar_src.src}`:
this.userAvatar;
this.behaviorSubject = new BehaviorSubject<string>('basicInfo');
this.behaviorSubjectObservable = this.behaviorSubject.asObservable();
this.setComponentBehaviorSubject(this.behaviorSubject);
this.behaviorSubjectSubscription = this.behaviorSubjectObservable.subscribe(data =>{
this.currentDisplayMenu = data;
});
}
ionViewWillLeave(){
this.behaviorSubjectSubscription.unsubscribe();
}
setDisplayMenuInfo(str){
this.showInfo(str);
}
async getUserData(){
return await this.storage.get('session_storage');
}
clearUserSession(){
this.oneSignal.removeExternalUserId();
this.storage.set('session_storage', null);
}
initializeApp() {
this.platform.ready().then(() => {
this.statusBar.styleLightContent();
this.splashScreen.hide();
this.setup();
if(this.platform.is('cordova')){
this.setupPush();
}
this.storage.get('session_storage').then((res)=>{
if(res == null){
this.router.navigateByUrl('log-in');
}
});
});
}
setupPush(){
this.oneSignal.startInit(oneSignalData.appId, oneSignalData.googleProjectNumber);
this.oneSignal.inFocusDisplaying(this.oneSignal.OSInFocusDisplayOption.Notification);
this.oneSignal.handleNotificationReceived().subscribe(data => {
//Do something when notification received...
/*let msg = data.payload.body;
let title = data.payload.title;
let additionalData = data.payload.additionalData;*/
});
this.oneSignal.handleNotificationOpened().subscribe(data => {
let additionalData = data.notification.payload.additionalData;
//Actions to take when notification opened...
});
this.getUserData().then(res =>{
if(res && res.data.username != "" && res.data.type_user != ""){
this.oneSignal.setExternalUserId(`${res.data.username};${res.data.type_user}`);
}else{
this.oneSignal.removeExternalUserId();
}
})
this.oneSignal.endInit();
}
}
where AppPages is simply another class imported by app.component.ts and inside i having the public static property pages, this is simply an array of objects, and inside each object i have some menu display properties, like the title and icon of each menu item, also, having another property, called detailTag, this tag allows me to easily show or hide some content of the menu depending to the property:
currentDisplayMenu
of app.component.ts, so some menu info is clasified by 'basicInfo' inside detailTag property, this means that when currentDisplayMenu have content 'basicInfo', i will only show the menu items that have the detailTag matching by 'basicInfo', the other clasification is 'accountInfo'.
Well, other file that is needed is menu_functionality.ts, which looks like:
import { BehaviorSubject } from 'rxjs';
var componentBehaviorSubject:BehaviorSubject<string>;
export function showInfo(tag){
switch(tag){
case 'basicInfo':
return componentBehaviorSubject.next('basicInfo');
break;
case 'accountInfo':
let CBS = componentBehaviorSubject.next('accountInfo');
this.menu.open();
return CBS;
break;
}
}
export function setComponentBehaviorSubject(behaviorSubject:BehaviorSubject<string>){
componentBehaviorSubject = behaviorSubject;
}
The reason of why i'm calling the this.menu.open(); function only when the tag is 'accountInfo', is because, the app.component.html and app.component.ts are working globaly in the app and if the user clicks only in the sidemenu button to open it there is no problem and no need to put it, but here is the thing and the real reason of why i'm using BehaviorSubject:
App.component.html and app.component.ts are shared, so there are no problems if the user hits in the menu opener button in one or other page of the app, but... the way i'm showing other info like 'accountInfo' is using an avatar which is not inside of app.component.html (is not shared) i wanted to put in another place instead of putting it in the menu, this is because i didn't know how to make it globally usable like app.component.html, so i have to write that html in each page.html that i want to use it.
and when user hits the avatar i need to only show the 'accountInfo' items in the menu and obviously open it, (this is why i only call this.menu.open when the tag is accountInfo), i don't know if there is another better way to make this.

NodeJS, Angular 2 | Executing method on Observable next

I'm currently getting started with Angular 2 and got stuck on something probably pretty simple:
I have a shared service chatMessageService.ts:
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable()
export class ChatMessageService {
private messageList = new BehaviorSubject<string>("");
currentMessage = this.messageList.asObservable();
constructor() {
}
public addMessage(msg:string) {
this.messageList.next(msg) }
}
The service is imported by two components, one that calls it's addMessage function to add the message to the Observable and then my chatComponent.ts looks like this (shortened fpr convinience):
import { Component } from '#angular/core';
import { Message } from './message';
import { ChatMessageService } from './chatMessage.service';
#Component({
selector: 'app-chat',
templateUrl: './chat.component.html',
styleUrls: ['./chat.component.css']
})
export class ChatComponent {
conversation: Message[] = [];
//.....
constructor(private chatMessageService: ChatMessageService) { }
addUserMessage(message) {
this.conversation.push({
content: message
});
}
ngOnInit() {
this.chatMessageService.currentMessage.subscribe(message => {this.addUserMessage(message);} )
}
}
My crisis arises at that last subscripion part. When I replace
{this.addUserMessage(message);}
with
{console.log(message)}
the message is printed out perfectly fine. If I call the addUserMessage()-method manually it works just fine. But when I call the method right there, with the message as argument, nothing happens. The method isn't even executed?
Thankful for your insights!
It looks like you need some buffering in the service.
Instead of BehaviorSubject, try
private messageList = new ReplaySubject<string>(10);
See working example: Plunker

Angular 4: Cannot instantiate cyclic dependency! InjectionToken_HTTP_INTERCEPTORS

I know, this question may sound duplicate and I have tried everything found on stackover flow unable to resolve this problem, so please bear with me
To make you able to reproduce the error I am providing you the whole code thought this
Github Repo
Problem
I am getting the following error:
Provider parse errors:↵Cannot instantiate cyclic dependency!
InjectionToken_HTTP_INTERCEPTORS ("[ERROR ->]"): in NgModule AppModule
in ./AppModule#-1:-1
Information about the scenario (Notes)
Note 1
File: response-interceptor.service.ts
Path: ./src/app/shared/interceptors/response-interceptor/
I am intercepting the HTTPClient responses to check the 401 error and when the error comes I need to ask user to re-login.
To show the re-login prompt to user I have made a global-functions-services that has a function 'relogin'
Note 2
File: global-function.service.ts
Path: ./src/app/shared/services/helper-services/global-function/
Here is the place where this all started to happen...
As soon as I am injecting the PersonService
constructor(
public dialog: MatDialog,
private _personService: PersonService
) { }
I am getting this error and in PersonService I cannot find any import that can cause the issue.
PersonService:
./src/app/shared/services/api-services/person/person.service.ts
import { IRequest } from './../../../interfaces/I-request';
import { environment } from 'environments/environment';
import { Injectable } from '#angular/core';
// for service
import 'rxjs/add/operator/map'
import 'rxjs/add/operator/toPromise';
// models
import { Person } from 'app/shared/models/person';
import { RequestFactoryService, REQUEST_TYPES } from 'app/shared/factories/request-factory/request-factory.service';
#Injectable()
export class PersonService {
private _requestService: IRequest;
constructor(
_requestFactoryService: RequestFactoryService
) {
this._requestService = _requestFactoryService.getStorage(REQUEST_TYPES.HTTP);
}
public signup(record): Promise<Person> {
let url = environment.api + 'person/public/signup';
return this._requestService.post(url, record) as Promise<Person>;;
}
public authenticate(code: string, password: string): Promise<Person> {
let url = environment.api + 'auth/signin';
let postData = {
code: code,
password: password
}
return this._requestService.post(url, postData) as Promise<Person>;
}
}
Request
Please suggest a solution for this, I have already wasted 2 days to figure out the issue but no luck.
Many thanks!! in advance
Cyclic dependency, means circling around endless, like planets orbiting sun..
Solution: Break the dependency chain, Re-factor code.
You have GlobalFunctionService -> PersonService -> so on... -> ResponseInterceptorService -> and back to -> GlobalFunctionService.
Cycle complete.
REMOVE the PersonService dependency from GlobalFunctionService. (its not used anyway, if you need it then find different way to get around.)
import { PersonService } from 'app/shared/services/api-services/person/person.service';
import { Injectable } from '#angular/core';
import { InputModalComponent } from 'app/shared/components/input-modal/input-modal.component';
import { MatDialog } from '#angular/material';
#Injectable()
export class GlobalFunctionService {
constructor(
public dialog: MatDialog
) { }
relogin(): void {
let dialogRef = this.dialog.open(InputModalComponent, {
width: '250px',
data: { title: "Please provide your password to re-login." }
});
dialogRef.afterClosed().subscribe(result => {
debugger
console.log('The dialog was closed');
let password = result;
});
}
}
Use setTimeout() function in constructor to assign service.
constructor(private injector: Injector) {
setTimeout(() => {
this.loginService = this.injector.get(LoginService);
})
}
Try this and revert back if you face any issue.
You have to modify your response-interceptor.service.ts
import { Injectable,Inject, Injector } from '#angular/core';
constructor( inj: Injector) {
this._globalFunctionService=inj.get(GlobalFunctionService)
}
You can get more info From this link

How to access functions created in the Component outside of Angular2 using JavaScript [duplicate]

I am using a javascript Object that has a callback. Once the callback is fired I want to call a function inside an Angular2 component.
example
HTML file.
var run = new Hello('callbackfunction');
function callbackfunction(){
// how to call the function **runThisFunctionFromOutside**
}
<script>
System.config({
transpiler: 'typescript',
typescriptOptions: { emitDecoratorMetadata: true },
packages: {'js/app': {defaultExtension: 'ts'}}
});
System.import('js/app/main')
.then(null, console.error.bind(console));
</script>
My App.component.ts
import {Component NgZone} from 'angular2/core';
import {GameButtonsComponent} from './buttons/game-buttons.component';
#Component({
selector: 'my-app',
template: ' blblb'
})
export class AppComponent {
constructor(private _ngZone: NgZone){}
ngOnInit(){
calledFromOutside() {
this._ngZone.run(() => {
this.runThisFunctionFromOutside();
});
}
}
runThisFunctionFromOutside(){
console.log("run");
}
How can i call the function runThisFunctionFromOutside which is inside App.component.ts
I basically followed this answer, but I didn't want my "outside" code to know anything about NgZone. This is app.component.ts:
import {Component, NgZone, OnInit, OnDestroy} from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: 'app.component.html'
})
export class AppComponent implements OnInit, OnDestroy {
constructor(private ngZone: NgZone) {}
ngOnInit() {
window.my = window.my || {};
window.my.namespace = window.my.namespace || {};
window.my.namespace.publicFunc = this.publicFunc.bind(this);
}
ngOnDestroy() {
window.my.namespace.publicFunc = null;
}
publicFunc() {
this.ngZone.run(() => this.privateFunc());
}
privateFunc() {
// do private stuff
}
}
I also had to add a definition for TypeScript to extend the window object. I put this in typings.d.ts:
interface Window { my: any; }
Calling the function from the console is now as simple as:
my.namespace.publicFunc()
See also How do expose angular 2 methods publicly?
When the component is constucted make it assign itself to a global variable. Then you can reference it from there and call methods.
Don't forget to use zone.run(() => { ... }) so Angular gets notified about required change detection runs.
function callbackfunction(){
// window['angularComponentRef'] might not yet be set here though
window['angularComponent'].zone.run(() => {
runThisFunctionFromOutside();
});
}
constructor(private _ngZone: NgZone){
window['angularComponentRef'] = {component: this, zone: _ngZone};
}
ngOnDestroy() {
window.angularComponent = null;
}
Plunker example1
In the browser console you have to switch from <topframe> to plunkerPreviewTarget.... because Plunker executes the code in an iFrame. Then run
window['angularComponentRef'].zone.run(() => {window['angularComponentRef'].component.callFromOutside('1');})
or
window.angularComponentRef.zone.run(() => {window.angularComponentRef.componentFn('2');})
An alternative approach
would be to dispatch events outside Angular and listen to them in Angular like explained in Angular 2 - communication of typescript functions with external js libraries
Plunker example2 (from the comments)
Below is a solution.
function callbackfunction(){
window.angularComponent.runThisFunctionFromOutside();
}
<script>
System.config({
transpiler: 'typescript',
typescriptOptions: { emitDecoratorMetadata: true },
packages: {'js/app': {defaultExtension: 'ts'}}
});
System.import('js/app/main')
.then(null, console.error.bind(console));
</script>
My App.component.ts
import {Component NgZone} from 'angular2/core';
import {GameButtonsComponent} from './buttons/game-buttons.component';
#Component({
selector: 'my-app',
template: ' blblb'
})
export class AppComponent {
constructor(private _ngZone: NgZone){
window.angularComponent = {runThisFunctionFromOutside: this.runThisFunctionFromOutside, zone: _ngZone};
}
runThisFunctionFromOutside(){
console.log("run");
}
}
An other approach without using global variables is to use pass a control object and bind its properties to the variables and methods to expose.
export class MyComponentToControlFromOutside implements OnChanges {
#Input() // object to bind to internal methods
control: {
openDialog,
closeDialog
};
ngOnChanges() {
if (this.control) {
// bind control methods to internal methods
this.control.openDialog = this.internalOpenDialog.bind(this);
this.control.closeDialog = this.internalCloseDialog;
}
}
internalOpenDialog(): Observable<boolean> {
// ...
}
internalCloseDialog(result: boolean) {
// ...
}
}
export class MyHostComponent {
controlObject= {};
}
<my-component-to-control [control]="controlObject"></my-component-to-control>
<a (click)="controlObject.open()">Call open method</a>
I had a similar situation when using the callback 'eventClick' of the fullCalendar library, whose callbacks are returning from outside the angular zone, causing my application to have partial and unreliable effects. I was able to combine the zone approach and a closure reference to the component as seen below in order to raise an output event. Once I started executing the event inside of the zone.run() method the event and it's effects were once again predictable and picked up by angular change detection. Hope this helps someone.
constructor(public zone: NgZone) { // code removed for clarity
}
ngOnInit() {
this.configureCalendar();
}
private configureCalendar() {
// FullCalendar settings
this.uiConfig = {
calendar: { // code removed for clarity
}
};
this.uiConfig.calendar.eventClick = this.onEventClick();
}
private onEventClick() {
const vm = this;
return function (event, element, view) {
vm.zone.run(() => {
vm.onSequenceSelected.emit(event.sequenceSource);
});
return false;
};
}
Just adding to #Dave Kennedy:
Calling the function from the console is now as simple as:
my.namespace.publicFunc()
1) If we try to access our component's public method from a different domain you will get caught into CORS issue (the cross origin problem, can be solved if both server and client code resides in same machine).
2) if you were to call this method from server using javascript, you will have to use window.opener.my.namespace.publicFunc() instead of window.my.namespace.publicFunc():
window.opener.my.namespace.publicFunc();

Categories