In my Ionic app, I have a List page that lists Alerts. This page also has a “Create Alert” button.
- Tapping on the list items opens a detail page displaying the details of that Alert.
- The button click should open the same detail page, but a blank one, in which the user can enter data to create an Alert and Save.
Tapping on list item is working fine, that is, it opens up the detail page and displays the contents of the Alert object I am passing over.
However, clicking on the “Create Alert” button does not open the same page. Nothing happens, no error. It does appear to overlap the same list page (or a blank one or something else) on top of itself. If I click the Back button it slides something. I think I know the reason why it is not loading the detail page. It’s because the Alert object that I use on the detail page is NULL/Undefined in scenario when the detail page is opened for creating an Alert. Now, because in the HTML I am referring to that object in [(ngModel)]
in all the components (input, select, etc.) and the object is NULL it is failing to load the page.
Would appreciate if somebody can confirm if I am doing it right or please suggest the right way to do it. Maybe, I need to use FormBuilder, FormControl and FormGroup. I have not used it till now so was trying to avoid it. Will do it if that’s the right way. Or perhaps that’s the only way to do it in my scenario.
Please help.
I am on MacOS with iPhone 6 Plus as device and latest version of everything.
Thank you!
Here is the code:
List Page HTML
<ion-header>
<ion-navbar color='navbarColor'>
<ion-title>Alert List</ion-title>
<ion-buttons end>
<button ion-button (click)="refresh()">
<i class="fa fa-refresh fa-2x" aria-hidden="true"></i>
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content padding>
<button block ion-button (click)="createAlert()">
Create Alert
</button>
<ion-list>
<ion-item detail-push *ngFor="let alert of alerts" (click)="editAlert(alert)">
<h2><b>Name: {{alert.profileName}}</b></h2>
<p>Type: {{alert.alertTypeName}}</p>
</ion-item>
</ion-list>
</ion-content>
List Page TypeScript
// All Imports here...
@Component({
selector: 'page-alert-list',
templateUrl: 'alert-list.page.html'
})
export class AlertListPage {
loading: Loading;
title = "Navbar Title";
alerts: AlertSubscriptionInfo[];
constructor(public navCtrl: NavController, public navParams: NavParams,
private loadingCtrl: LoadingController, public alertService: AlertService,
private alertCtrl: AlertController, private toastCtrl: ToastController,
private events: Events) {
}
ionViewDidLoad() {
console.log('AlertListPage->ionViewDidLoad().');
this.getAlertList();
}
getAlertList() {
this.showLoading();
this.alertService.getAlerts().then(
(res) => {
setTimeout(() => {
this.loading.dismiss();
this.alertSubscriptions = res.result;
});
},
(error) => {
this.showError(error);
}
);
}
refresh() {
this.getAlertList();
}
createAlert() {
this.navCtrl.push(AlertDetailPage, { "title": 'Add Alert' });
}
editAlert(alert: AlertSubscriptionInfo) {
this.navCtrl.push(AlertDetailPage, { "title": 'Edit Alert', "alert": alert });
}
showLoading() {
this.loading = this.loadingCtrl.create({
content: 'Please wait...'
});
this.loading.present();
}
showError(text) {
setTimeout(() => {
this.loading.dismiss();
});
let alert = this.alertCtrl.create({
title: 'Error',
subTitle: text,
buttons: ['OK']
});
alert.present();
}
}
Detail Page HTML
<ion-header>
<ion-navbar color='navbarColor'>
<ion-title>{{title}}</ion-title>
<ion-buttons end>
<button (click)="saveAlert()" color="blue" ion-button icon-only>
Done
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-item>
<ion-label stacked>Alert Profile Name</ion-label>
<ion-input [(ngModel)]="currentAlert.profileName" value={{currentAlert.profileName}}></ion-input>
</ion-item>
<ion-item>
<ion-label>Alert Type</ion-label>
<ion-select [(ngModel)]="currentAlert.alertTypeId">
<ion-option *ngFor="let alertType of alertTypes" value="{{alertType.alertTypeId}}">
{{alertType.alertName}}
</ion-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Alert Level</ion-label>
<ion-select [(ngModel)]="selectedAlertLevel" (ionChange)="alertLevelChanged();">
<ion-option *ngFor="let alertLevel of alertLevels" value="{{alertLevel}}">
{{alertLevel.level}}
</ion-option>
</ion-select>
</ion-item>
<button block ion-button (click)="openHierarchyPage()" [disabled]="disableHierarchyButton">
Add Hierarchy
</button>
<ion-item *ngIf="currentAlert.hierarchy.length > 0" >{{currentAlert.hierarchy.length}} store(s) selected.</ion-item>
<ion-item-divider color="light"><b>Subscription Mode</b></ion-item-divider>
<ion-item>
<ion-label>Push Notification</ion-label>
<ion-toggle [(ngModel)]="currentAlert.enabled" checked={{currentAlert.enabled}}></ion-toggle>
</ion-item>
<button block ion-button icon-start outline color="danger" *ngIf="alertSubscriptionId" (click)="deleteSubscription(alertSubscriptionId)">
<i class="fa fa-trash fa-2x" aria-hidden="true"></i>
Delete Alert
</button>
</ion-content>
Detail Page TypeScript
// All Imports here...
@Component({
selector: 'page-alert-add',
templateUrl: 'alert-add.page.html'
})
export class AlertAddPage {
loading: Loading;
title: string;
currentAlert: AlertSubscriptionInfo;
alertTypes: AlertTypeInfo[];
alertLevels: AlertLevelInfo[];
selectedAlertLevel: AlertLevelInfo;
disableHierarchyButton: boolean;
constructor(public navCtrl: NavController, public navParams: NavParams,
private loadingCtrl: LoadingController, private alertCtrl: AlertController,
public alertSettingsService: AlertSettingsService, private events: Events) {
this.currentAlert = this.navParams.get('alert');
this.title = this.navParams.get('title');
}
ionViewDidLoad() {
console.log('In AlertAddPage->ionViewDidLoad().');
this.showLoading();
this.alertSettingsService.getAlertTypes().then(
(res) => {
this.alertTypes = res.result;
},
(err) => {
this.showError(err);
}
);
this.alertSettingsService.getLevels().then(
(res) => {
this.loading.dismiss();
this.alertLevels = res.result;
},
(err) => {
this.showError(err);
}
);
this.checkToDisableHierarchyButton();
}
//TODO: Temporary, use a Service Provider class instead by injecting it in the pages that needs data back-and-forth
myCallbackFunction = (_params) => {
return new Promise((resolve, reject) => {
this.currentAlert = _params;
resolve();
});
}
validateAlert(): boolean {
if (this.currentAlert.profileName == null) {
this.showValidationMessage('Alert Profile Name', 'Please enter a valid Alert Profile Name.');
return false;
}
else if (this.currentAlert.alertTypeId == null) {
this.showValidationMessage('Alert Type', 'Please select an Alert Type.');
return false;
}
else if (this.currentAlert.levelOrder == null) {
this.showValidationMessage('Level', 'Please select an Alert Level.');
return false;
}
else if (this.currentAlert.hierarchy.length == 0) {
this.showValidationMessage('Hierarchy', 'Please select Hierarchy Level(s).');
return false;
}
return true;
}
saveAlert() {
if(this.validateAlert()) {
this.showLoading();
this.alertSettingsService.saveAlert(this.currentAlert)
.then(
(httpreq) => {
setTimeout(() => {
this.loading.dismiss();
this.events.publish('alertCreate:success');
this.navCtrl.pop();
});
},
(error) => {
this.showError(error);
}
);
}
}
showValidationMessage(titleStr: string, msg: string): void {
let alert = this.alertCtrl.create({
title: titleStr,
message: msg,
buttons: [
{
text: 'Ok',
role: 'OK',
handler: () => {
console.log('OK Clicked.');
}
}
]
});
alert.present();
}
checkToDisableHierarchyButton(): void {
if(this.currentAlert.levelOrder > 0) {
this.disableHierarchyButton = false;
}
else {
this.disableHierarchyButton = true;
}
}
openHierarchyPage() {
this.navCtrl.push(AlertStoresPage, { "alert": this.currentAlert, 'callback': this.myCallbackFunction });
}
public alertLevelChanged(): void {
this.currentAlert.levelOrder = this.selectedAlertLevel.levelOrder;
this.currentAlert.levelName = this.selectedAlertLevel.level;
this.checkToDisableHierarchyButton();
}
deleteSubscription(alertSubscriptionId: number) {
this.showLoading();
this.alertSettingsService.deleteScubscription(alertSubscriptionId)
.subscribe(
(result) => {
setTimeout(() => {
this.loading.dismiss();
if (result) {
this.events.publish('alertDelete:success');
this.navCtrl.pop();
}
else {
this.showError('Server Error. Please try later. Or contact your Technical Support.')
}
});
},
(error) => {
this.showError(error);
}
);
}
showLoading() {
this.loading = this.loadingCtrl.create({
content: 'Please wait...'
});
this.loading.present();
}
showError(text) {
setTimeout(() => {
this.loading.dismiss();
});
let alert = this.alertCtrl.create({
title: 'Error',
subTitle: text,
buttons: ['OK']
});
alert.present();
}
}