I have this modal in an Angular app:
<ng-template #content let-modal>
<div >
<h2 id="modal-basic-title">{{saveTitle}}</h2>
<button type="button" aria-label="Close" (click)="modal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div >
<app-add-program [model]="model" [showNavBar]="false" title=""></app-add-program>
</div>
<div >
<button type="button" (click)="modal.close('Save click')">{{saveButtonTitle}}</button>
</div>
</ng-template>
I don't think the app-add-program
component is really necessary to answer this question but if you need to see it let me know.
This is the open function for that modal:
open(content): void {
// @ts-ignore
this.modalReference = this.modalService.open(content, {ariaLabelledBy: 'modal'}).result.then((result) => {
this.pds.programCast.subscribe((data) => {
if (result === 'Save click'){
const editedProgram = data;
console.log('Edited program: ', editedProgram);
const validity = this.programService.validateModel(editedProgram);
console.log('Validity check...');
if (validity.isValid === true) {
console.log('Validity was true.');
// If the program needs to be approved and activated then mark it approved
if (editedProgram?.approved === false){
editedProgram.approved = true;
}
if (editedProgram?.active === false){
editedProgram.active = true;
}
console.log(editedProgram);
console.log('Starting api call...');
if (editedProgram != null && editedProgram !== undefined) {
this.programService.editProgram(editedProgram).subscribe({
// tslint:disable-next-line:no-shadowed-variable
next: result => {
this.wasSuccessful = true;
console.log('It was successful');
this.snackBar.open('Your changes have been saved.');
this.modalReference.close();
},
error: err => {
this.wasSuccessful = false;
console.log('It failed: ', err.statusText);
this.snackBar.open('There was an error saving your changes. Error Status ' err.status ': ' err.statusText);
}
});
}
} else {
console.log('Validity was false.');
this.snackBar.open(validity.reason);
}
} else {
this.closeResult = `Closed with: ${result}`;
}
});
}, (reason) => {
this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
});
}
What I want is rather than calling modal.close
in the html call a function instead that makes the API call and either close the modal with this.modalReference.close()
if it was successful or leave the modal open if it was not successful.
So basically, this section needs to execute:
const editedProgram = data;
console.log('Edited program: ', editedProgram);
const validity = this.programService.validateModel(editedProgram);
console.log('Validity check...');
if (validity.isValid === true) {
console.log('Validity was true.');
// If the program needs to be approved and activated then mark it approved
if (editedProgram?.approved === false){
editedProgram.approved = true;
}
if (editedProgram?.active === false){
editedProgram.active = true;
}
console.log(editedProgram);
console.log('Starting api call...');
if (editedProgram != null && editedProgram !== undefined) {
this.programService.editProgram(editedProgram).subscribe({
// tslint:disable-next-line:no-shadowed-variable
next: result => {
this.wasSuccessful = true;
console.log('It was successful');
this.snackBar.open('Your changes have been saved.');
this.modalReference.close();
},
error: err => {
this.wasSuccessful = false;
console.log('It failed: ', err.statusText);
this.snackBar.open('There was an error saving your changes. Error Status ' err.status ': ' err.statusText);
}
});
}
} else {
console.log('Validity was false.');
this.snackBar.open(validity.reason);
}
and then in the next
clause call this.modalReference.close()
or leave it open and present the pop up message that it shows in the error
clause.
I know that I have most of the code written already but for some reason I just can't work out in my head how to write the code to execute in that order.
If you need any further info to answer this question please let me know.
UPDATE:
open(content): void {
// @ts-ignore
this.modalReference = this.modalService.open(content, {ariaLabelledBy: 'modal'}).result;
}
private validateAndSave(closeReason) {
if (closeReason === 'Save click') {
const editedProgram = this.model;
console.log('Model: ', this.model);
console.log('Edited program: ', editedProgram);
if (editedProgram != null && editedProgram !== undefined) {
const validity = this.programService.validateModel(editedProgram);
if (validity.isValid === true) {
console.log('Validity was true.');
// If the program needs to be approved and activated then mark it approved
if (editedProgram?.approved === false) {
editedProgram.approved = true;
}
if (editedProgram?.active === false) {
editedProgram.active = true;
}
this.programService.editProgram(editedProgram).subscribe({
next: result => {
this.wasSuccessful = true;
console.log('It was successful: ', result);
this.snackBar.open('Your changes have been saved.');
this.modalReference.close();
},
error: err => {
this.wasSuccessful = false;
console.log('It failed: ', err.statusText);
this.snackBar.open('There was an error saving your changes. Error Status ' err.status ': ' err.statusText);
}
});
} else {
console.log('Validity was false.');
this.snackBar.open(validity.reason);
}
}
} else {
this.modalReference.close();
}
}
<button type="button" (click)="validateAndSave('Save click')">{{saveButtonTitle}}</button>
I believe that I have done everything that the first answer recommended but I am getting this error when trying to close the modal:
[Error] ERROR – TypeError: _this.modalReference.close is not a function.
CodePudding user response:
You are executing all your code in the resolve
path of your modal.
To avoid that, simply create a new function (validateAndSave
or something like that) and move all the logic starting from the third line of your open
function
That would be this part:
this.pds.programCast.subscribe((data) => {...}
But you have to remove the first if
of that block, the one that checks:
if (result === 'Save click') {...}
So, when you reach your wasSuccessful
case, you simply call this.modalReference.close()
Finally, in your template you call the validateAndSave
function instead of the modal.close
:
<button type="button" (click)="validateAndSave()">{{saveButtonTitle}}</button>
Don't forget to remove the .then
part of your opening modal line, so it will only open the modal and store the reference in this.modalReference