1

I am successfully using ng bootstrap and specifically the modal module to show a modal form. It is a contact form that has email and message input fields and a submit button. The ngbootstrap module I am using is https://ng-bootstrap.github.io/#/components/modal/examples this shows fine. What I am trying to do is that when user clicks on the 'send' button (see template code below) the button will become disabled and say 'sending...'. In other words I'm trying to manipulate the properties view the modal component.

I have already looked at the following questions but none of the suggestions work:

Angular 2 @ViewChild annotation returns undefined How to get reference of the component associated with ElementRef in Angular 2

However no matter what, I get 'undefined' when I try to use in my component

@ViewChild('submitButton') submitButton: ElementRef;

along with this html in my template

<button #submitButton
   id="submitButton"
   class="btn btn-success w-100"
   [disabled]="!contactForm.valid"
>Send</button>

Here is the full component code (the place where I am trying to access the submitButton is in method onSubmit()):

import {
    Component,
    OnInit,
    Renderer2,
    ViewChild,
    ElementRef,
    AfterViewInit
} from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { NgbModal, ModalDismissReasons } from '@ng-bootstrap/ng-bootstrap';

import { ContactService } from '../../services/contact.service';

@Component({
    selector: 'app-contact-modal',
    templateUrl: './contact-modal.component.html'
})
export class ContactModalComponent implements OnInit, AfterViewInit {

    closeResult: string;
    contactForm: FormGroup;
    //@ViewChild('submitButton') submitButton;
    @ViewChild('submitButton') submitButton: ElementRef;

    constructor(
        private modalService: NgbModal,
        private contactService: ContactService,
        private renderer: Renderer2
    ) { }

    ngOnInit() {
        this.initForm();
    }

    ngAfterViewInit() {
        console.log(this.submitButton);
    }

    private getDismissReason(reason: any): string {
        if (reason === ModalDismissReasons.ESC) {
          return 'by pressing ESC';
        } else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
          return 'by clicking on a backdrop';
        } else {
          return  `with: ${reason}`;
        }
    }

    private initForm() {
        const email = '';
        const message = '';

        this.contactForm = new FormGroup({
            email: new FormControl(null, Validators.email),
            message: new FormControl(null, Validators.required)
        });
    }

    onSubmit() {

        const email = this.contactForm.value.email;
        const message = this.contactForm.value.message;

        // at this point this.submitButton is UNDEFINED
        console.log(this.submitButton);

        //this.submitButton.nativeElement.style.backgroundColor = 'black';

        this.contactService.sendContactRequest(email, message, (submitSuccess: boolean) => {
            if (submitSuccess) {

                console.log('SUCCESS UPDATE UI');
                this.contactForm.value.email = '';
                this.contactForm.value.message = '';

            } else {
                console.log('ERROR update UI');
            }
        });
    }

    open(content) {
        console.log('in open func');
        this.modalService.open(content, {ariaLabelledBy: 'modal-basic-title'})
        .result
        .then(
            (result) => {
                console.log(`Closed with: ${result}`);
            },
            (reason) => {
                console.log(`Dismissed ${this.getDismissReason(reason)}`);
            }
        );
    }
}

Here is my full template:

<a
    class="nav-link"
    (click)="open(content)"
><i class="fas fa-envelope"></i></a>

<ng-template #content let-c="close" let-d="dismiss">

    <div class="modal-header">
        <h4 class="modal-title" id="modal-basic-title">Contact Us</h4>
        <button type="button" class="close" aria-label="Close" (click)="c()">
          <i class="fas fa-times"></i>
        </button>
    </div>

    <div class="modal-body">

        <form [formGroup]="contactForm" (ngSubmit)="onSubmit()">

            <div class="row justify-content-center">

                <div class="col-md-12 col-sm-12">
                    <div class="form-group">
                        <label for="email">Email</label>
                        <input
                            type="text"
                            class="form-control"
                            id="email"
                            formControlName="email"
                        >
                    </div>
                </div>

            </div>

            <div class="row justify-content-center">

                <div class="col-md-12 col-sm-12">
                    <div class="form-group">
                        <label for="message">Message</label>
                        <textarea
                            type="text"
                            class="form-control"
                            id="message"
                            formControlName="message"
                            rows="6"
                        ></textarea>
                    </div>
                </div>

            </div>

            <div class="row justify-content-center">

                <div class="col-md-12 col-sm-12">
                    <button #submitButton
                        id="submitButton"
                        class="btn btn-success w-100"
                        [disabled]="!contactForm.valid"
                    >Send</button>
                </div>

            </div>

            <div class="row">
                <div class="col-md-12 col-sm-12">
                    <div *ngIf="sentMessage" class="alert alert-success" role="alert">
                        {{ sentMessage }}
                    </div>
                </div>
            </div>

        </form>

    </div>

</ng-template>

Any help is greatly appreciated.

Sergey
  • 995
  • 4
  • 14
  • 33
  • can you add your code in stackblitz – Chellappan வ Aug 22 '18 at 03:27
  • Your template code inside ng-template. Where you are inserting into the DOM? – Suresh Kumar Ariya Aug 22 '18 at 03:42
  • @SureshKumarAriya your comment gave me the hint I needed - I have to get the template with TemplateRef like so: @ViewChild('content') content: TemplateRef; found at https://stackoverflow.com/questions/42567236/viewchildren-for-ng-template. However this only gets the template itself #content (see the template code above) - now that I have the template, how do I get the children of the template, specifically #submitButton???? – Pippy Longstocking Aug 22 '18 at 13:35
  • You need to get ElementRef using @ViewChild('content', {read: ElementRef}) content: ElementRef;. Then you can query the inner child elements using querySelector. this.content.nativeElement.querySelector('.btn-classname'). You need to assign unique class name to the button. – Suresh Kumar Ariya Aug 22 '18 at 16:21
  • 1
    @SureshKumarAriya I did what you specified and getting "HeaderComponent.html:61 ERROR TypeError: this.content.nativeElement.querySelector is not a function" : @ViewChild('content', {read: ElementRef}) content: ElementRef; - when i console.log(this.content); I see ElementRef {nativeElement: comment} but querySelector is not part of the object.... – Pippy Longstocking Aug 22 '18 at 18:49
  • any updates on this? – iBlehhz Sep 12 '19 at 08:56
  • Could it be because the modal is conditional? This answer seems to suggest that if it's hidden by something, it won't resolve: https://stackoverflow.com/a/52540563/1718312 – Shafiq Jetha Jul 22 '20 at 15:45

1 Answers1

0

What I am trying to do is that when user clicks on the 'send' button (see template code below) the button will become disabled and say 'sending...'. In other words I'm trying to manipulate the properties view the modal component.

//this.submitButton.nativeElement.style.backgroundColor = 'black';

if I understand the question (and your code) correctly, you basically want to do three things:

  1. Set button to disabled after clicking on send
  2. Set button text to ''sending...''
  3. Set button background color to black (in your code)

You can do the first two by data binding (Types of data binding). For the third one I found a workaround, to get it working (using the dom, instead of angular @Viewchild).

  1. You can use a boolean-variable in the typescript file (e.g. ''isDataSent: boolean'') which you OR with the ''!isValid'' in the HTML
  2. You specify the displayed text in the .ts file with a variable and use Data Binding to show it
  3. You access the dom element by id, set the color and remove the ''@ViewChild('submitButton') submitButton: ElementRef;'' line. If you want to do all the things by accessing the dom, you can do it also this way :-)

Here is sample code (which lines omitted can be seen as untouched, comments with )

Change the HTML-Button to:

          <button
              id="submitButton"
              class="btn btn-success w-100"
              [disabled]="!contactForm.valid || isDataSent"
          >{{submitButtonText}}</button>

So in the typescript file:

export class ContactModalComponent implements OnInit, AfterViewInit {
  // ... code ...
  isDataSent: boolean;
  submitButtonText: string;
  // ... code ...
  ngOnInit() {
    //... code ...
    this.isDataSent = false;
    this.submitButtonText = 'Send';
    //... code ...
  }
  // ... code ...
  onSubmit() {
    const email = this.contactForm.value.email;
    const message = this.contactForm.value.message;

    const submitButton = document.getElementById('submitButton');
    if (submitButton) {
      submitButton.style.backgroundColor = 'black';
    } 
    this.submitButtonText = 'sending...';
    this.isDataSent = true;
    
    this.contactService.sendContactRequest(email, message, (submitSuccess: boolean) => {
        if (submitSuccess) {

            console.log('SUCCESS UPDATE UI');
            this.contactForm.value.email = '';
            this.contactForm.value.message = '';

        } else {
            console.log('ERROR update UI');
        }
    });
  }
  //... code ...
}

I'm using Angular CLI: 11.2.8 and Node: 14.16.0.
Hope this helps, if you have any improvements on my answer, please let me know.
-Alex

Thinklex
  • 83
  • 6