Home > database >  Angular close a bootstrap modal conditionally
Angular close a bootstrap modal conditionally

Time:04-28

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">&times;</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

  • Related