I got a problem where I cannot load a pdf inside a view of my app.
In my demo app for this I got two views, one "home" and one "result". In the home view I got a button which opens an android document picker with function pickDocument(). After a document has been picked the file name and file path get passed to the "result" view.
In my result view I convert the given path of the document picker to a native path in setPath(), but this path gives me a 404 on my device. I can't seem to load the file I want to display there.
The file has the local path (before converting it using setPath():
content://com.android.providers.downloads.documents/document/22
I get the following error:
Dummy-PDF.pdf:1 GET http://localhost/_app_file_/storage/emulated/0/Download/Dummy-PDF.pdf 404 (OK)
Is there anything I am missing? Or is there a better way to do, what I am trying to do? Could someone please help me to fix this issue.
I included the important code parts below. Thanks a lot.
Code of home.page.ts
...
export class HomePage {
constructor(private chooser: Chooser, private router: Router) { }
pickDocument() {
this.chooser.getFile("application/pdf")
.then(file => {
this.addFile(file.name, file.uri);
}, error => {
console.error(error);
});
}
addFile(fileName: string, fileUri: string) {
let navigationExtras: NavigationExtras = {
queryParams: {
"fileName": fileName,
"fileUri": fileUri
}
};
this.router.navigate(["result"], navigationExtras);
}
}
Code of result.page.ts
...
export class ResultPage implements OnInit {
public fileName: string;
public fileUri: string;
public path: string;
private win: any = window;
constructor(private route: ActivatedRoute, private filePath: FilePath) {
this.route.queryParams.subscribe(params => {
this.fileName = params["fileName"];
this.fileUri = params["fileUri"];
this.setPath();
});
}
ngOnInit() {
}
setPath() {
this.filePath.resolveNativePath(this.fileUri).then(path => {
this.path = this.win.Ionic.WebView.convertFileSrc(path);
});
}
}
Code of result.page.html
<ion-content>
<ion-list>
<ion-item>
<ion-img [src]="path"></ion-img>
</ion-item>
<ion-item>FileName: {{fileName}}</ion-item>
<ion-item>FileUri:{{fileUri}}</ion-item>
<ion-item>FilePath:{{path}}</ion-item>
</ion-list>
</ion-content>
Related
I'm working with Spring boot and angular, and I'm trying to create a route in angular that could be used in image tag <img src="..."> as an image link (this link also calls a spring boot API).
My Spring boot API is something like that http://localhost:8080/api/v1/event?aff_id=1, it returns an image file.
My Angular route is http://client1.localhost:4200/event?aff_id=1,
This one (Angular route) worked perfectly when I run it directly from the browser, it calls the Spring boot API.
But when I use it in the image tag like that <img src="http://client1.localhost:4200/event?aff_id=1"> it shows 404 (Not Found), because my angular component in this case returns an HTML page.
Does anyone have an idea to fix this, please?
This is my component code:
export class TrackConversionComponent implements OnInit {
urlQuery: any;
constructor(private activatedRoute: ActivatedRoute,
private trackingLeadService: TrackingLeadService) {
this.activatedRoute.queryParams.subscribe((params) => {
this.urlQuery = params;
});
}
ngOnInit(): void {
this.trackingLeadService.track(this.urlQuery,'conversion').subscribe(res => {
new Promise((resolve, reject) => {
this.createImageFromBlob(res);
})
});
}
createImageFromBlob(image: Blob) {
const reader = new FileReader();
reader.addEventListener('load', () => {
console.log(reader.result)
}, false);
reader.readAsDataURL(image);
}
track(paramObj, event){
this.trackingLeadService.track(paramObj,event).subscribe(
{
next: (v) => console.log(v),
error: (e) => console.log(e),
complete: () => console.log('complate')
}
);
return true;
}
}
PS1: The HTML template of this component is a blank page.
PS2: I can't use the Spring Boot API link directly in the image tag because I send some data in HttpHeader to Spring Boot project.
UPDATE
According to #brain solution, I got this from the Angular Route:
I created an Electron - Angular project where I can do a screenshot remotely, this generate this blob (I name it as ssUrl / this.ssUrl in the code below)
I don't want it to be saved locally but instead to be uploaded directly to firebase storage, I've been following some documentations and altering it a bit to fit my codebase, however this generates an error.
Here is my code:
import {
AngularFirestore,
AngularFirestoreCollection,
} from '#angular/fire/compat/firestore';
import { Observable, concatWith } from 'rxjs';
import {
AngularFireStorage,
AngularFireUploadTask,
} from '#angular/fire/compat/storage';
#Component({
selector: 'app-autoupload',
templateUrl: './autoupload.component.html',
styleUrls: ['./autoupload.component.scss'],
})
export class LoginComponent implements OnInit {
constructor(
private afs: AngularFirestore,
private afsU: AngularFireStorage
) {}
checkSS() {
if (this.ssRequest == true) {
this.getScreenshot(); // executes IpcServices to get screenshot using electron
console.log('ready to upload', this.ssUrl); // generated URL from electron
// Uploading to Firebase storage
this.imagePathName = 'gallery' + Math.random();
this.imageRef = this.afsU.ref(this.imagePathName);
this.imageRef.putString(this.ssUrl, 'base64', {contentType: 'image/png'});
this.imageSub = this.imageBaseRef
.snapshotChanges()
.pipe(concatWith(this.imageRef.getDownloadURL()))
.subscribe((url: Observable<string>) => {
this.downloadUrl = url;
this.galleryUrl = this.downloadUrl;
this.galleryLogDate = new Date();
this.afs.collection('gallery').add({
ssUrl: this.galleryUrl,
profileId: this.loggedProfileId,
userName: this.loggedUsername,
});
});
}
}
}
generates two error
I know there's something wrong on how I upload it using putString or maybe I'm using the wrong method on storage ref. I tried other approaches but also ending up getting more errors
this.imageBaseRef = this.afsU.upload(this.imagePathName, this.ssUrl);
Hopefully you could correct what me or guide me on how to fix.
I am using Stripe checkout with my Angular 5 project and seem to be stuck on a router redirect / template lifecycle issue.
On user signup, I open the stripe checkout modal. When that modal get's a payment source token, I do some more API work and then do a router.redirect.
stripe.open({
email: 'foo#foo.com',
name: 'Subscription',
description: 'Basic Plan',
amount: 499,
token: (source) => {
this.http.post('/user/subscribe', { source: source.id }).subscribe(_ => {
this.router.navigate(['stylist/profile']);
});
}
});
The app redirects properly, but the variables do not display whatsoever. Below is an example of my page. Ideally, the redirect would trigger the ngOnInit and the test variable would be true. In my scenario, the test is displayed in the html template as blank.
Profile Route
{ path: 'stylist/profile', component: ProfilePageComponent, canActivate: [AuthGuard] },
Auth Guard
#Injectable()
export class AuthGuardService implements CanActivate {
constructor(
public auth: AuthService,
public router: Router,
public route: ActivatedRoute
) {}
canActivate(): boolean {
if (!this.auth.isAuthenticated()) {
this.router.navigate(['']);
return false;
}
return true;
}
}
Profile Page Component
export class ProfilePageComponent implements OnInit {
test: boolean = false;
ngOnInit() {
this.test = true;
}
}
Profile Page HTML
<div>Test variable: {{test}}</div>
This code has been simplified, but I wanted to make sure I wasn't missing any strange lifecycle events due to redirecting in a callback of a callback?
I've tried subscribing to various Router and ActivatedRoute events without any luck. I've also seen solutions involving ngZone, but those didn't seem to fit the bill either.
01/07/19 UPDATE
I was able to recreate this via stackblitz per the suggestion in the comments.
https://stackblitz.com/edit/angular-un9tfk
Upon initial load of the homepage, you can click the "Open Stripe" button and fill out some dummy data. The callback then redirects to /test with a warning message in the console.
Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'?
I believe this points me to doing ngZone.run()... somewhere in my signup.component.ts, but not sure where just yet.
As stated in the edit above, it turns out using Router.navigate in a function callback is technically outside of an Angular zone.
Wrapping my Router.navigate in NgZone.run(() => {}) did the trick.
Implemented solution:
import { Component, Input, NgZone } from '#angular/core';
constructor(private zone: NgZone) { }
signup() {
stripe.open({
email: 'foo#foo.com',
name: 'Subscription',
description: 'Basic Plan',
amount: 499,
token: (source) => {
this.http.post('/user/subscribe', { source: source.id }).subscribe(_ => {
this.zone.run(() => {
this.router.navigate(['stylist/profile']);
});
});
}
});
}
I am trying to use intercom in my app to monitor user activity.
its working fine when I put inside script tag in index.html
but when I try to use in .ts file I am getting below error.
app/components/rocket/rocket-search.ts(63,10): error TS2339: Property 'intercomSettings' does not exist on type 'Window'.
can you tell me how to fix it.
providing my code below
not working code
import { Component, ElementRef, Input, Output, EventEmitter, Inject, OnInit, ViewChild } from '#angular/core';
import { KendoGridComponent } from '../grid/grid.component'
import { Router } from '#angular/router';
import { sportsService } from '../../services/sports.service';
#Component({
selector: 'rocketSearch',
templateUrl: "./app/components/rocket/rocket-search.html",
})
export class rocketSearch {
/* Localization variables */
#Output() rocketSearchEmitter: EventEmitter<any> = new EventEmitter<any>();
private dataSourceVal;
private MainGrid;
private grid;
private titles;
public rocketRef;
constructor( public elementRef: ElementRef, public router: Router, public sportsService: sportsService) {
}
private kendocommand = {
edit: { createAt: "bottom" },
autoBind: false,
excelFileName: {
fileName: "",
allPages: true
}
}
ngOnInit() {
let that = this;
let attributes = this.sportsService.getSeesionStorageValue();
// if (attributes) {
// this.userId = attributes.user_attributes.SSO[0];
// }
//app/components/rocket/rocket-search.ts(63,10): error TS2339: Property 'intercomSettings' does not exist on type 'Window'.
window.intercomSettings = {
app_id: 'irgooiqb',
name: "Jane Doe", // Full name
email: "customer#example.com", // Email address
created_at: 1312182000 // Signup date as a Unix timestamp
};
//console.log(.log(this.userId);
}
}
working code inside index.html
<script>
(function(){var w=window;var ic=w.Intercom;if(typeof ic==="function"){ic('reattach_activator');ic('update',intercomSettings);}else{var d=document;var i=function(){i.c(arguments)};i.q=[];i.c=function(args){i.q.push(args)};w.Intercom=i;function l(){var s=d.createElement('script');s.type='text/javascript';s.async=true;s.src='https://widget.intercom.io/widget/APP_ID';var x=d.getElementsByTagName('script')[0];x.parentNode.insertBefore(s,x);}if(w.attachEvent){w.attachEvent('onload',l);}else{w.addEventListener('load',l,false);}}})()
</script>
<script>
let players=this.sportsService.marksSession();
console.log("players--->" + players);
if(players) {
this.userId = players.user_players.SSO[0];
}
Intercom('trackEvent', 'share-link');
window.intercomSettings = {
app_id: 'APP_ID',
name: "Jane Doe", // Full name
email: "customer#example.com", // Email address
created_at: 1312182000 // Signup date as a Unix timestamp
};
</script>
well it wouldn't work, the code in your html actually fetches the intercom js library from the URL https://widget.intercom.io/widget/APP_ID which the code in your typescript do not.
A better approach is to install the intercom npm package that you can then import in your code, however I don't write typescript so I'm unsure if there would be any issue using the package in a typescript fashion.
Is there a way to refresh only a page i.e. only one screen in ionic2.
I tried :
window.location.reload();
and
location.reload();
but it rebuilds the app .. is there a way to refresh only that page (particular screen).
Also tried:
<ion-input *ngIf="no_internet === 1" (click)="refresh($event)"></ion-input>
in TypeScript:
refresh(refresher) {
console.log('Begin async operation', refresher);
setTimeout(() => {
console.log('Async operation has ended');
refresher.complete();
}, 2000);
}
Try this code :
this.navCtrl.setRoot(this.navCtrl.getActive().component);
You could also use the ionic refresher, to create a pull to refresh action on the page
http://ionicframework.com/docs/v2/api/components/refresher/Refresher/
I would do that : (based on #Ahmad Aghazadeh answer)
this.navCtrl.push(this.navCtrl.getActive().component).then(() => {
let index = this.viewCtrl.index;
this.navCtrl.remove(index);
})
=> Push this page once more (loading it again)
=> Remove the page we were on (using index)
Example of using ion-refresher in an async function in ionic 3:
in your .html file:
<ion-content no-padding >
<ion-refresher (ionRefresh)="doRefresh($event)">
<ion-refresher-content></ion-refresher-content>
</ion-refresher>
and in your .ts file:
constructor(...) {
...
samplefuncion(null){
asyncFunction().then(()=>{
...//after success call
...
if (event)
event.complete();
},(error)=>{
....
if (event)
event.complete();
})
}
doRefresh(event) {
samplefuncion(event);
}
If you are willing to follow a common convention, I have found a very easy way to reload the current view (including all of its parameters). I tested this using Ionic3, but it should still apply in Ionic 2
Move all of your initialization code for every page into ionViewDidLoad(), which is run ONCE on the first time the view is loaded
import { Component } from '#angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { Api } from '../../providers/api';
import { Movie } from '../../interfaces/movie';
#Component({
selector: 'page-movie-info',
templateUrl: 'movie-info.html'
})
export class MovieInfoPage {
constructor(
public navCtrl: NavController,
public navParams: NavParams,
public api: Api
) {
}
/**
* Run all page initialization in this method so that this page
* can be refreshed simply by re-calling this function
*/
ionViewDidLoad() {
//access any parameters provided to the page through navParams.
var movieId = this.navParams.data.movieId;
this.api.movies.getById(movieId).then((movie) => {
this.movie = movie;
});
}
public movie: Movie;
}
From anywhere else in the app, you can reload the current view with this code
//get the currently active page component
var component = this.navController.getActive().instance;
//re-run the view load function if the page has one declared
if (component.ionViewDidLoad) {
component.ionViewDidLoad();
}
Html:
<ion-refresher (ionRefresh)="doRefresh($event)">
<ion-refresher-content></ion-refresher-content>
</ion-refresher>
</ion-content>
TypeScript :
#Component({...})
export class NewsFeedPage {
doRefresh(refresher) {
console.log('Begin async operation', refresher);
setTimeout(() => {
console.log('Async operation has ended');
refresher.complete();
}, 2000);
}
}
source : Ionic doc
Try this, just pop one page and then push that page again.
this.navCtrl.pop();
this.navCtrl.push(NewPage);
Hope this will help.
Try this: $window.location.reload(); $route.reload() use to reload route.
if you are using $stateProvider : $state.go($state.current, {}, {reload: true});
or
var currentPageTemplate = $route.current.templateUrl;
$templateCache.remove(currentPageTemplate);
$route.reload();