ionic 2 use zone Ngzone() - ionic2

hi i try to use Zone on my ionic2 app :
i create a provider who take location of my device
import { Injectable,NgZone } from '#angular/core';
import { Geolocation, Geoposition } from '#ionic-native/geolocation';
import 'rxjs/add/operator/filter';
#Injectable()
export class LocationTracker {
public watch: any;
public lat: number = 0;
public lng: number = 0;
constructor(public zone: NgZone,
public geolocation:Geolocation) {
console.log('Hello LocationTracker Provider');
}
startTracking() {
console.log("provider startTracking")
let options = {
frequency: 3000,
enableHighAccuracy: true
};
this.watch = this.geolocation.watchPosition(options).filter((p: any) => p.code === undefined).subscribe((position: Geoposition) => {
// Run update inside of Angular's zone
this.zone.run(() => {
this.lat = position.coords.latitude;
this.lng = position.coords.longitude;
});
});
}
}
In the home view html, i have access to the zone with {{locationTracker.lat}}, but in my home component (who call this provider) i don't know how i can't have access to the zone
i try this
this.locationTracker.lat
but it's undefined
can't you help my ?

Related

Angular app keeps saying message does not exist

I'm building a chat app with Angular and Django using the get stream tutorial. https://getstream.io/blog/realtime-chat-django-angular/
However, I'm trying to run the app to create the chat view but it keeps saying 'messages' does not exist at the point marked 'this point' in the code.
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { MessageResponse, Channel } from 'stream-chat';
import { StreamService } from '../stream.service';
import { StateService } from '../state.service';
declare const feather: any;
#Component({
selector: 'app-chat',
templateUrl: './chat.component.html',
styleUrls: ['./chat.component.scss'],
})
export class ChatComponent implements OnInit {
constructor(
public streamService: StreamService,
private stateService: StateService,
private router: Router
) {}
messages: MessageResponse[] = [];
message = '';
channel!: Channel;
async sendMessage() {
if (this.message) {
try {
await this.channel.sendMessage({
text: this.message,
});
this.message = '';
} catch (err) {
console.log(err);
}
}
}
getClasses(userId: string): { outgoing: boolean; incoming: boolean } {
const userIdMatches = userId === this.streamService.currentUser.messages.id; (this point)
return {
outgoing: userIdMatches,
incoming: !userIdMatches,
};
}
}

Angular View does't refresh on array push

I am very new to ionic and angular.
Anyway, I am trying to following an tutorial to create a notes app using ionic4 https://www.joshmorony.com/building-a-notepad-application-from-scratch-with-ionic/.
So, I follow the instruction. Everything is ok except that the view doesn't updated when I add new note. The code is as follow:
Note services:
import { Injectable } from '#angular/core';
import { Storage } from '#ionic/storage';
import { Note } from '../interfaces/note';
#Injectable({
providedIn: 'root'
})
export class NotesService {
public notes: Note[] = [];
public loaded: boolean = false;
constructor(private storage: Storage) {
}
load(): Promise<boolean> {
// Return a promise so that we know when this operation has completed
return new Promise((resolve) => {
// Get the notes that were saved into storage
this.storage.get('notes').then((notes) => {
// Only set this.notes to the returned value if there were values stored
if (notes != null) {
this.notes = notes;
}
// This allows us to check if the data has been loaded in or not
this.loaded = true;
resolve(true);
});
});
}
save(): void {
// Save the current array of notes to storage
this.storage.set('notes', this.notes);
}
getNote(id): Note {
// Return the note that has an id matching the id passed in
return this.notes.find(note => note.id === id);
}
createNote(title): Promise<boolean> {
return new Promise((resolve) => {
// Create a unique id that is one larger than the current largest id
let id = Math.max(...this.notes.map(note => parseInt(note.id)), 0) + 1;
this.notes.push({
id: id.toString(),
title: title,
content: ''
});
this.save();
console.log('Service Log ' + this.notes);
resolve(true);
});
}
}
The HTML code:
<ion-header>
<ion-toolbar color="primary">
<ion-title>Notes</ion-title>
<ion-buttons slot="end">
<ion-button (click)="addNote()">
<ion-icon slot="icon-only" name="clipboard"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item button detail *ngFor="let note of notesService.notes" [href]="'/notes/' + note.id" routerDirection="forward">
<ion-label>{{ note.title }}</ion-label>
</ion-item>
</ion-list>
</ion-content>
I've followed the same tutorial and got the same issue. The issue is because of something very interesting and powerful called Zones.
The idea is that you'd need to let Angular know that the array with the notes has changed, by doing something like this:
// Angular
import { Component, NgZone } from '#angular/core';
// Ionic
import { NavController, AlertController } from '#ionic/angular';
// Services
import { NotesService } from '../services/notes.service';
import { AlertOptions } from '#ionic/core';
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
constructor(
private ngZone: NgZone, // Add this in the constructor
private navCtrl: NavController,
private alertCtrl: AlertController,
private notesService: NotesService,
) { }
ngOnInit() {
this.notesService.load();
}
addNote() {
const alertOptions: AlertOptions = {
header: 'New Note',
message: 'What should the title of this note be?',
inputs: [
{
type: 'text',
name: 'title'
}
],
buttons: [
{
text: 'Cancel'
},
{
text: 'Save',
handler: (data) => {
// Create the note inside a Zone so that Angular knows
// that something has changed and the view should be updated
this.ngZone.run(() => {
this.notesService.createNote(data.title);
});
}
}
]
};
this.alertCtrl
.create(alertOptions)
.then((alert) => {
alert.present();
});
}
}

Angular 2: BehaviorSubject/Subject does not work outside constructor

Hi I need pass the data from one component to another, for this I am using the class BehavorSubject(I tried too with Subject class, but doesnt works for me). This is my code:
Home page has a filter, and when is selected a filter, it called the service and it service should change a variable of homePage
HomePage.ts
#Component({
providers: [PatientService],
})
export class HomePage {
subscription: Subscription;
constructor( public auth: AuthService,
public patientService: PatientService) {
this.subscription = this.patientService.nameGiven.subscribe(
nameGiven => {
this.patientsByElement = nameGiven.toString();
});
------ more code---
}
Filtro.ts
export class FiltroPage {
showFilter(filter : FiltroT): void{
... code ...
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
this.PatientService.getPatientsByTags(this.token,this.filterSelected);
} , 1000);
}
}
patient-service.ts
import { Subject } from 'rxjs/Subject';
import { Observable ,BehaviorSubject } from 'rxjs/Rx';
#Injectable()
export class PatientService {
nameSource = new BehaviorSubject("asd");
nameGiven = this.nameSource.asObservable();
this.nameSource.next('hi!!!'); //**it works but only in the constructor**
this.nameGiven.subscribe(()=>{
console.log("it changed");
});
getPatientsByTags(token: String, tags: Array<string>){
return new Promise(resolve => {
this.http.get(ConnectionParams.DevEnv + ProceduresNames.TagsByPatient + ProceduresNames.TagIdEtiqueta + tags, options)
.map(res => res.json())
.subscribe(data => {
if(data.data.poAnicuRegistros){
console.log("here")
this.nameSource.next('hi TON :/'); // <-- ***here is the problem. It doesnt work***
}
else
console.log("XX");
resolve( this.data);
});
});
}
}
Finally i didn't use the BehaviorSubject/Subject, i pass the data from the filter to Homepage of this way :
HomePage.ts
public popoverCtrl: PopoverController
//code ...
showFilter(myEvent) {
let popover = this.popoverCtrl.create(FiltroPage, {
showConfirm: (x) => {
//do something with the data received from the filter
}
});
popover.present({
ev: myEvent
});
}
Filter.ts
//code...
params: NavParams;
showConfirm() {// function that return the data to homePage
this.params.get('showConfirm')(this.patientsBytag);
}

cordova.fileTransfer not updating page template Ionic2+Cordova

I have created an Ionic2 App using cordova FileTransferplugin, i am downloading remote server file.
Everything is working perfectly, but when I try to update template while fileTransfer.OnProgress event, the template is not updating the % downloaded.
Pleas see this video for my problem.
Ionic_youtube_link
My Code is, logic is in downloadFile function
import {Component, AfterViewInit, ViewChild} from '#angular/core';
import {NavController, NavParams, ViewController, Nav} from 'ionic-angular';
import {Page, Platform} from 'ionic-angular';
import {File, Device, Cordova, Transfer} from 'ionic-native';
import { SafeResourceUrl, DomSanitizationService } from '#angular/platform-browser';
#Component({
templateUrl: 'build/pages/video-download-modal/video-download-modal.html',
providers: [File, Transfer]
})
export class VideoDownloadModal {
selectedItem: any;
#ViewChild(Nav) nav: Nav;
videoPathUrl: string;
isPlatformReady: boolean;
platformName: string;
directoryName: string = "socialAppDir";
totalVideoSize:number;
totalDownloaded:number;
totalPercent:string = "0%";
constructor(public navCtrl: NavController, navParams: NavParams, private _viewController: ViewController, platform: Platform, private transfer:Transfer) {
// If we navigated to this page, we will have an item available as a nav param
if (platform.is('core')) {//if on dekstop
console.log('dektop');
} else {
this.videoPathUrl = navParams.get('videoPath');
console.log(this.videoPathUrl);
platform.ready().then((readySource) => {
this.isPlatformReady = true;
console.log('ready 1234');
const fs: string = cordova.file.externalRootDirectory;
console.log(cordova.file.dataDirectory);
this.platformName = Device.device.platform;
File.checkDir(cordova.file.externalDataDirectory, this.directoryName).then(() => {
console.log('directory exists');
this.downloadFile();
}, (error) => {
console.log('directory not exists');
this.createDirectory();
})
})
}
}
dismiss() {
let data = { 'foo': 'bar' };
this._viewController.dismiss(data);
}
createDirectory():void{
File.createDir(cordova.file.externalDataDirectory, this.directoryName, true).then(() => {
console.log("created externalDataDirectory");
this.downloadFile();
},(error) => {
console.log('some error happen')
})
}
downloadFile = () => {
console.log(this);
let fileName: string = this.videoPathUrl.split("/").pop();
let targetPath = cordova.file.externalDataDirectory + this.directoryName + "/" + fileName;
console.log(targetPath);
this.transfer.download(this.videoPathUrl, targetPath, true, {}).then(() => {
console.log('video downloaded')
}, (error) => {
console.log(error)
})
this.transfer.onProgress((progress) => {
console.log(this);
this.totalVideoSize = progress.total;
this.totalDownloaded = progress.loaded;
this.totalPercent = ((progress.loaded / progress.total) * 100).toString();
console.log(this.totalPercent);
})
}
ionViewDidEnter() {
console.log("enter login1");
}
}
And HTML is
<ion-content>
<div id="modalContainer" class="abd">
<ion-spinner></ion-spinner>
<br />
{{**totalPercent**}}
<br />
<button dnager block (click)="dismiss()">Exit</button>
</div>
</ion-content>
The totalPercent value either has 0 or 100.But not updating.
Please help.
This is because the totalPercent of this inside the handler was set to the global Window object instead of the object itself.
I have finally got it to work
import { NgZone } from '#angular/core';
fileTransfer.onProgress((progressEvent: ProgressEvent) => {
this.ngZone.run(() => {
if (progressEvent.lengthComputable) {
let lp = progressEvent.loaded / progressEvent.total * 100;
this.loadingPercent = Math.round(lp * 100) / 100;
}
});
})

How to access FB global from Angular2 service?

I'm trying to use FB SDK from an Angular2 project created with the new angular CLI. I created the following service to initialize the Facebook library, added fbsdk typings and everything compiles but I cant access the FB global variable from anywhere in the project but the "winwow.fbAsyncInit" function. I can check FB object from console perfectly, but cant access it from NG2 code. ¿Any idea of where the problem might be?
import { Injectable, OnInit } from '#angular/core'
import { FACEBOOK_APPID } from '../constants'
#Injectable()
export class fbService implements OnInit{
constructor(){}
ngOnInit(){
if (!window.fbAsyncInit) {
window.fbAsyncInit = function () {
FB.init({
appId: FACEBOOK_APPID,
xfbml: false,
version: 'v2.6'
});
FB.api("/me",null,()=>{})
console.log(FB)
};
}
this.initFB()
}
initFB(){
var js, id = 'facebook-jssdk', ref = document.getElementsByTagName('script')[0];
if (document.getElementById(id)) {
return;
}
js = document.createElement('script');
js.id = id;
js.async = true;
js.src = "//connect.facebook.net/en_US/sdk.js";
ref.parentNode.insertBefore(js, ref);
}
getPost(page:string){
FB.api(`/${page}/feed?limit=1`,null,(response)=>{console.log(response)})
}
}
The key is in the call to this.zone.run(callback) to wrap the callback and reinsert it in the Angular 2 lifecycle.
I initialize the SDK in the service constructor, which may introduce some delay compared to loading it right away. Haven't found a workaround yet.
I still haven't decided if I'll provide an accessor to FB once initialized or wrapper methods, I'll leave that to you.
#Injectable()
export class FbsdkService {
public ready = new BehaviorSubject<boolean>(false);
constructor(
private zone: NgZone) {
this.loadSdkAsync(() => {
FB.init({
appId: "XXXXXXXXXXX",
status: false,
xfbml: false,
version: "v2.7"
});
this.ready.next(true);
});
}
loadSdkAsync(callback: () => void) {
window.fbAsyncInit = () => this.zone.run(callback);
// Load the Facebook SDK asynchronously
const s = "script";
const id = "facebook-jssdk";
var js, fjs = document.getElementsByTagName(s)[0];
if (document.getElementById(id)) return;
js = document.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs)
}
}
I had similar issue and this source helped me a lot- Building CrossPlatform Desktop Applications with Electron
import { Injectable, NgZone } from '#angular/core';
import { BehaviorSubject } from "rxjs/Rx";
import { Http } from '#angular/http';
declare var FB: any;
#Injectable()
export class FbsdkService {
public ready = new BehaviorSubject<boolean>(false);
public endpointBase = 'http://graph.facebook.com';
constructor(private zone: NgZone, private http: Http) {
}
public loadSdk() {
this.loadAsync(() => { });
}
public loadAsync(callback: () => void) {
window.fbAsyncInit = () => this.zone.run(callback);
const s = "script";
const id = "facebook-jssdk";
var js: any, fjs = document.getElementsByTagName(s)[0];
if (document.getElementById(id)) return;
js = document.createElement(s);
js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}
public getLoginStatus() {
FB.getLoginStatus((response: any) => { console.log(response); });
}
public getProfile() {
return new Promise((resolve, reject) => {
let fields = [
"id", "name", "email", "cover", "birthday"
];
FB.api(`/me?fields=${fields.toString()}`, (response: any) => {
resolve(response);
});
});
}
}