I've built a small alert service (wrapper for Angular AlertController) in my Ionic 4 project, it works perfectly when I view the project in "ionic serve" (browser), "ionic cordova emulate" (on my connected phone), "ionic cordova build android" (installing the app-debug APK manually on my phone) however when I build the release version of the app using "ionic cordova build android --prod --release" the "message" part of the Alert does not show. The header (title) and the buttons show and work fine still, but the message does not appear.
Here is my method which creates and presents the alert:
/**
* "Confirm" with callback or "Cancel" alert
*/
async confirmOrCancelAlert(title, message, callback) {
const alert = await this.alertController.create({
header: title,
message: message,
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
}, {
text: 'Confirm',
handler: () => {
callback();
}
}
]
});
await alert.present();
}
This is the code which called the method shown above, which is called from a button click:
/**
* Answer questions button event click
*/
answerQuestions() {
if (this.shift.getEarly() && (this.shift.getTimeToStart().asHours() > environment.alertTimes.answerQuestions)) {
var timeTo = this.durationFormatPipe.transform(this.shift.getStart());
var message = 'Your shift starts ' + timeTo + ', are you sure you want to answer questions now?';
this.alertService.confirmOrCancelAlert('You are early!', message, () => {
this.doAnswerQuestions();
});
} else {
this.doAnswerQuestions();
}
}
Here are two images showing the message messing from the release build but showing in the serve / emulate / debug builds:
Many thanks in advance for any and all advice.
I think it's a timing problem. when you call confirmOrCancelAlert() the timeTo is not prepared yet. so the type of message will be undefined.
try this:
answerQuestions() {
if (this.shift.getEarly() && (this.shift.getTimeToStart().asHours() > environment.alertTimes.answerQuestions)) {
var timeTo = this.durationFormatPipe.transform(this.shift.getStart());
var message = 'Your shift starts ' + timeTo + ', are you sure you want to answer questions now?';
setTimeout(() => {
this.alertService.confirmOrCancelAlert('You are early!', message, () => {
this.doAnswerQuestions();
});
}, 50);
} else {
this.doAnswerQuestions();
}
}
try this:
async confirmOrCancelAlert(title, myMessage, callback) {
const alert = await this.alertController.create({
header: title,
message: myMessage,
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
}, {
text: 'Confirm',
handler: () => {
callback();
}
}
]
});
await alert.present();
}
change the name to myMessage to make it different than property name. message: message will cause a problem I think I had the same problem last year. check it out and inform me of the results.
Related
In my ionic app, I need to open a specific page after receiving a push notification.
I'm testing it in the Android Studio emulator and have displayed a bunch of console logs that prove that the push.on('notification').subscribe event is definitely triggering the page using navCtrl.push (I've tried navCtrl.setRoot too) and the ngOnInit is doing everything as normal and making it to the end of its code.
The problem is that after that, the page just isn't showing.
I can see the following message in the Android console log, but I don't really know what it means:
D/SystemWebChromeClient: ng:///AppModule/ShiftDetailsPage.ngfactory.js: Line 563 : ERROR
I/chromium: [INFO:CONSOLE(563)] "ERROR", source: ng:///AppModule/ShiftDetailsPage.ngfactory.js (563)
but they appear before all the console log messages output by ngOnInit in ShiftDetailsPage, so I guess they don't mean there was a problem loading the page.
Another thing that is appearing is:
Cannot read property 'controls' of undefined.
in the app.
I've searched everywhere for someone having a similar problem, but all I can find are descriptions of how to receive notifications, but nothing helpful about how to trigger pages from the event.
Should I use something other than navCtrl.push or is that the correct way?
Any suggestions are very welcome.
Here's the code in the push.on subscribe:
push.on('notification').subscribe(async (data: EventResponse) => {
console.log("in notification, data = " + JSON.stringify(data));
if (data.additionalData.shiftId != null
&& data.additionalData.shiftId != ""
&& await this.login.isLoggedIn()
) {
console.log("in notification, shiftId = " + data.additionalData.shiftId);
console.log("in notification, isLoggedIn = " + JSON.stringify(await this.login.isLoggedIn()));
const confirmAlert = this.alertCtrl.create({
title: 'Shift Notification',
message: data.additionalData.shiftId,
buttons: [
{
text: 'Ignore',
role: 'cancel'
},
{
text: 'View',
handler: () => {
console.log("in notification, handler");
this.shiftDetailsProvider.getShiftDetails(data.additionalData.shiftId).then( async shift => {
const userLocation = await this.getUserLocation().then(userLocation => {
console.log("in pushSetup on notification, userLocation = ", userLocation);
return userLocation;
});
this.navCtrl.push(ShiftDetailsPage, {shift: shift, userLocation: userLocation, sourcePage: "notification"});
});
}
},
]
});
confirmAlert.present();
} else {
console.log("in notification, else");
if (data.additionalData.foreground) {
console.log("in notification, foreground");
const confirmAlert = this.alertCtrl.create({
title: 'New Notification',
message: data.message,
buttons: [
{
text: 'Cancel',
role: 'cancel'
},
{
text: 'OK',
handler: () => {
console.log('New notification callback')
}
},
]
});
confirmAlert.present();
if (this.platform.is('ios')) {
console.log("in notification, platform is ios");
push.finish(data.additionalData.notId);
}
} else {
console.log('Push notification clicked from the background');
}
}
});
I have the error like in question, when I'm trying to design my application to call native.camera, I see my console in ionic 3 project, I saw this error :
Native : tried calling Camera.getPicture, but Cordova is not available. Make sure to include cordova.js or run in a device / simulator.
Here is the code that I used to called native camera.
This is the code in my problem.html
<button class="logoCamera" ion-button (click)="presentActionSheet()">
<ion-icon name="camera" ></ion-icon>
This is the code in my problem.ts
import { File } from '#ionic-native/file';
import { Transfer, TransferObject} from '#ionic-native/transfer';
import { FilePath } from '#ionic-native/file-path';
import { Camera } from '#ionic-native/camera';
public presentActionSheet(){
let actionSheet = this.actionSheetCtrl.create({
title: 'Select Image',
buttons: [
{
text: 'Load from Library',
handler: () => {
this.takePicture(this.camera.PictureSourceType.PHOTOLIBRARY);
}
},
{
text: 'Use Camera',
handler: () => {
this.takePicture(this.camera.PictureSourceType.CAMERA);
}
},
{
text: 'Cancel',
role: 'cancel'
}
]
});
actionSheet.present();
}
public takePicture(sourceType){
//Create option for the Camera dialog
var options = {
quality: 100,
sourceType : sourceType,
saveToPhotoAlbum: false,
correctOrientation: true
};
//Get the data of an image
this.camera.getPicture(options).then((imagePath) => {
//special handling for android lib
if(this.platform.is('android') && sourceType === this.camera.PictureSourceType.PHOTOLIBRARY) {
this.filePath.resolveNativePath(imagePath)
.then(filePath => {
let correctPath = filePath.substr(0, filePath.lastIndexOf('/') + 1 );
let currentName = imagePath.substring(imagePath.lastIndexOf('/') + 1, imagePath.lastIndexOf('?'));
this.copyFileToLocalDir(correctPath, currentName, this.createFileName());
});
} else {
var currentName = imagePath.substr(imagePath.lastIndexOf('/') + 1);
var correctPath = imagePath.substr(0, imagePath.lastIndexOf('/')+ 1);
this.copyFileToLocalDir(correctPath, currentName, this.createFileName());
}
}, (err) => {
this.presentToast('Error while selecting Image.');
});
}
//Create a new name for image
private createFileName() {
var d = new Date(),
n = d.getTime(),
newFileName = n + ".jpg";
return newFileName;
}
//copy image to local folder
private copyFileToLocalDir(namePath, currentName, newFileName) {
this.file.copyFile(namePath, currentName, cordova.file.dataDirectory, newFileName).then(success => {
this.lastImage = newFileName;
}, error => {
this.presentToast('Error while storing file.');
});
}
private presentToast(text) {
let toast = this.toastCtrl.create({
message: text,
duration: 3000,
position: 'middle'
});
toast.present();
}
public pathForImage(img){
if (img === null) {
return '';
} else {
return cordova.file.dataDirectory + img;
}
}
public uploadImage() {
//destination URL
var url = "";
//file to upload
var targetPath = this.pathForImage(this.lastImage);
//file name only
var filename = this.lastImage;
var options = {
fileKey: "file",
fileName: filename,
chunkedMode: false,
mimeType: "multipart/form-data",
params: {'fileName': filename}
};
const fileTransfer: TransferObject = this.transfer.create();
this.loading = this.loadingCtrl.create({
content: 'Uploading...',
});
this.loading.present();
//use FileTransfer to upload image
fileTransfer.upload(targetPath, url, options).then(data => {
this.loading.dismissAll()
this.presentToast('Image successful uploaded.');
}, err => {
this.loading.dismissAll()
this.presentToast('Error while uploading file.');
});
}
When I run ionic serve, everything is smooth, no error, no nothing.
But when I click my button to access natve camera, the error shows, please help me figure out the problem, I check a lot of web, and none of it solve my question.
After I try run ionic cordova run ios --simulator, there are error coming out, but I am pretty sure that this error does not exist before I run this command.
May I know how to solve this problem ??
The error message is pretty accurate here:
Native : tried calling Camera.getPicture, but Cordova is not available. Make sure to include cordova.js or run in a device / simulator.
Running ionic serve does not include cordova.js nor does it run your application in a simulator or on a device which is why you get the error. You can fix it either by running your application on the device or simulator:
ionic cordova run android/ios --device/--simulator
Or by adding the browser platform:
cordova platform add browser
And running the browser platform:
ionic cordova run browser
I want to display a group notification instead of multiple notifications like whatsapp does.
For eg:
One notification with message - "2 discussions 1 comment" instead of
total three notifications.
I used react-native-fcm library (https://github.com/evollu/react-native-fcm)
I used group & tag keys but couldn't achieve the result as below code
FCM.presentLocalNotification({
title: 'Title',
body: 'Body',
priority: "high",
click_action: true,
show_in_foreground: true,
local: true,
group: 'group1',
tag: 'tag1'
});
Is it possible to achieve this functionality in react native FCM? Please let me know.
The project react-native-fcm is moved under react-native-firebase and there is a solution under this issue on the project.
The main idea:
The trick is to create an additional notification that will contain the notifications for that group.
// ID for grouping notifications, always the same
const SUMMARY_ID = `${ALERTS_GROUP}.summary`
const sendIt = (notification: Firebase.notifications.Notification) => {
return firebase.messaging().hasPermission().then((yes) => {
if (yes) {
try {
return firebase.notifications().displayNotification(notification)
.catch((err) => {
Log.e(`[sendNotification] ERROR: ${err}`)
return Promise.resolve()
})
} catch (err) {
Log.e('[sendNotification] Error displaying notification: ' + err)
}
}
return Promise.resolve()
})
}
const sendSummary = (data: MessageData) => {
const summary = new firebase.notifications.Notification()
.setNotificationId(SUMMARY_ID)
.setTitle(_T('notification.channels.alert.description'))
.setData(data)
.android.setAutoCancel(true)
.android.setCategory(firebase.notifications.Android.Category.Message)
.android.setChannelId(getChannelId(MsgType.Alert))
.android.setColor(variables.scheme.primaryColor)
.android.setSmallIcon(STATUS_ICON)
.android.setGroup(ALERTS_GROUP)
.android.setGroupSummary(true)
.android.setGroupAlertBehaviour(firebase.notifications.Android.GroupAlert.Children)
sendIt(summary)
}
/**
* Called by `bgMessaging` or the `onMessage` handler.
*/
export function sendNotification (message: Firebase.messaging.RemoteMessage) {
const payload: MessagePayload = message.data as any || {}
const notification = new firebase.notifications.Notification()
// ... more code
if (Platform.OS === 'android' && Platform.Version >= 24) {
notification.android.setGroup(ALERTS_GROUP)
sendSummary(notification.data)
}
Log.v('[sendSummary] sending notification.')
return sendIt(notification)
}
I wrote a script to detect if there is a wifi connection or not. However, I noticed, that if the app starts when there is no wifi connection, the splashscreen will load and then i'll get a white screen. The console shows this error:
Failed to load resource: net::ERR_INTERNET_DISCONNECTED
this is my script for detecting the wifi and its placed in the '$ionicPlatform.ready':
$rootScope.$on('$cordovaNetwork:offline', function(event, networkState)
{
connectionerror($ionicPopup)
})
//display error msg and close the app.
function connectionerror($ionicPopup,$scope)
{
var myPopup = $ionicPopup.show({
title: 'Network Error',
content: 'No internet connectivity detected. Please try again.',
buttons: [
{
text: '<b>Retry</b>',
type: 'button-positive',
onTap: function(e)
{
if (!$cordovaNetwork.isOnline())
{
e.preventDefault();
}
else
{
$state.reload();
}
}
}]
});
}
How do I fix it so that after the splashscreen, if there is no wifi, the message would show ?
The error happens when you are trying to load a resource from your pc probably. If you are running ionic serve or ionic serve live and you disconnect the wifi, the app will try to load a template form your pc using wifi and won't be able to do it.
To test that script you should build the app and run it on a device.
If that's working, the controller should be working differently. It should look more like this:
.controller('controller', function($scope, $rootScope, $state, $ionicPopup, $cordovaNetwork){
$rootScope.$on('$cordovaNetwork:offline', function(event, networkState)
{
connectionerror()
})
//display error msg and close the app.
function connectionerror()
{
var myPopup = $ionicPopup.show({
title: 'Network Error',
content: 'No internet connectivity detected. Please try again.',
buttons: [
{
text: '<b>Retry</b>',
type: 'button-positive',
onTap: function(e)
{
if (!$cordovaNetwork.isOnline())
{
e.preventDefault();
}
else
{
//go to a state like index or home instead of reload. Reload resets the application and should be avioded in single page apps
$state.go('...');
}
}
}]
});
}
})
I am building an application for iOS and Android using Appaccelerator. It works perfectly fine on Android, but throws 'undefined' error every time I try to open it on iOS devices. The weird thing is, it doesnt show a proper error message.
First I thought it is a build issue, so I cleaned the project, and then rebuilt it, but it was not the case. I also manually deleted the build folder, and rebuild, but still no improvement.
Here is the code :
Rf.media.photo = {
key: 'photo',
title: 'Photo',
extension: 'jpg',
type: 'image/jpeg',
create: function(created) {
Ti.media.showCamera({
animated: false,
saveToPhotoGallery: false,
showControls: true,
success: function() {
var name = Rf.util.timestamp() + '.' + Rf.media.photo.extension;
Rf.write_to_new_file(name, media_item.media, function(file) {
created(file);
});
},
error:function(error)
{
// create alert
var a = Titanium.UI.createAlertDialog({title:'Camera'});
// set message
if (error.code == Titanium.Media.NO_CAMERA)
{
a.setMessage('Please run this test on device');
}
else
{
a.setMessage('Unexpected error: ' + error.code);
}
// show alert
a.show();
},
cancel:function()
{
},
});
}
};
I get this error message when people clikc on the "Photo" button.
[WARN] Exception in event callback. {
line = 1;
message = "'undefined' is not an object (evaluating 'Ti.Media.showCamera')";
name = TypeError;
sourceId = 52935904;
sourceURL = "file://localhost/var/mobile/Applications/F8398B04-78C4-4A45-BEE0-30EE4BFEBB00/App.app/photo.js";
Is there a way to "initialize" the Ti.Media.showCamera(); method, so it would not find itself 'undefined'?
Ti.media.showCamera({... should be Ti.Media.showCamera({...
Also, in the success callback, there are no arguments to receive the returned media data. You have media_item.media in your write_to_new_file() function, so your success callback should probably read: success: function(media_item) {...