5
votes

I'm working on a modal dialog that I need to be able to dynamically change out the templateURL for dynamically. What's shown is the default template. I'm just wondering about how to achieve that as this would be called with the templateURL name and location being passed in. Below is my component code :

import { ModalService } from './../../services/modal.service';
import {Component, Input} from '@angular/core';

import {NgbModal, NgbActiveModal} from '@ng-bootstrap/ng-bootstrap';

@Component({
  selector: 'app-ngbd-modal-content',
  templateUrl: '../../templates/modal.tp1.html'
})

export class ModalOptionsComponent {
  @Input() name;

  constructor(public activeModal: NgbActiveModal, modelService: ModalService) {}
}

export class  NgbdModalComponent {
  constructor(private ngbModal: NgbModal) {}
}

Ideally I'd like to open it from my service class below versus the component but I'm not really sure how to do that. I've done quite a fair bit of research but I'm not finding much on how to accomplish this.

Modal.service.ts:

import { ModalOptionsComponent } from './../pages/modal-options/modal-options.component';
import { Injectable } from '@angular/core';
import {NgbModal, NgbActiveModal} from '@ng-bootstrap/ng-bootstrap';

@Injectable()
export class ModalService {

  constructor(private ngbModal: NgbModal, private modalComp: ModalOptionsComponent) { }

  modalService(modal: any) {
    const modalDefaults = {
      templateUrl: '../templates/modal.tp1.html'
    };
    const modalOptions = {
      hasClose: true,
      closeButtonText: 'CLose',
      actionButtonText: 'OK',
      headerText: 'Proceed?',
      bodyText: 'Perform this action?',
      okResult: {}
    };
  }

  showModal(customModalDefaults: any, cusomeModalOptions: any) {

  }


}

One of the things I'm needing to do is create service class for this as well I'm very new to angular and wondering how to acheive this.

2
I do this in my app, instead of creating different templateURL's, I just use *ngIf's to seperate what to show. You could also use variables in the component and that will change any text conditionally. Good luck! - BSchnitzel
@BSchnitzel unfortunately there are already .html's created that I have to use. - yams
Also could put templates in skinny html components and call them in a generic modal template conditionally <modal-body><*ngIf=""><template-1></template-1><*ngIf=""><template-2></template-2></modal-body> Can you do that or are you stuck with them as it? - BSchnitzel
Build each template as its own component then dynamically load them as needed. angular.io/guide/dynamic-component-loader - JC Ford
@JC Ford I agree - BSchnitzel

2 Answers

1
votes

Because there's not the ability that I can find to change out the templateUrl I had to make do with creating a component for each type of dialog I needed. The downside to this was that it was no longer dynamic but it suits what I need it for. And basically you can use the service to generate the type of component needed. One thing that is unfortunate is using dynamic component loading wasn't really a viable solution because of the complexity of doing it. Below is an example of what I did.

Component code for default modal dialog:

import {Component, Input} from '@angular/core';

import {NgbModal, NgbActiveModal} from '@ng-bootstrap/ng-bootstrap';

@Component({
  selector: 'app-ngbd-modal-content',
  template: `
<div class="modal-header">
<h3 class="font-32" style="padding-bottom: 0px">{{headerText}}</h3>
</div>
<div class="modal-body">
<p>{{bodyText}}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-dark" (click)="activeModal.close('Close click')">Close</button>
</div>
  `,
  styleUrls: ['./default-modal-dialog.component.scss']
})
export class DefaultModalDialogComponent {
  @Input() bodyText;
  @Input() headerText;

  constructor(public activeModal: NgbActiveModal) {}

}

Component code for FeaturedSearch:

    import {Component, Input} from '@angular/core';

    import {NgbModal, NgbActiveModal} from '@ng-bootstrap/ng-bootstrap';

    @Component({
    selector: 'app-featured-search-dialog',
    template: `
    <div>
        <div class="modal-header">
            <h3 class="font-32" style="margin-bottom: -16px;">Edit Heading and Subheading</h3>
        </div>
        <div class="modal-body" style="padding:30px;">
            <div class="row">
                <div class="col-md-12">
                    <label class="font-14-bold">Heading</label>
                </div>
            </div>
            <div class="row">
                <div class="col-md-12">
                    <input style="box-shadow: rgb(102, 102, 102) 0px 0px 4px inset; border: 0px; margin-bottom: 50px;"  type="text" class="form-control input-sm" ng-model="modalOptions.okResult.heading" >
                </div>
            </div>
            <div class="row">
                <div class="col-md-12">
                    <label class="font-14-bold">Subheading</label>
                </div>
            </div>
            <div class="row">
                <div class="col-md-12">
                    <input style="box-shadow: rgb(102, 102, 102) 0px 0px 4px inset; border: 0px;" type="text" class="form-control input-sm" ng-model="modalOptions.okResult.subheading" >
                </div>
            </div>
        </div>
        <div class="modal-footer">
            <div style="margin-top: 8px; margin-bottom: 8px;">
                <button style="background-color: #999999; color: #ffffff;" type="button" ng-show="modalOptions.okResult.buttonText !== 'Close'"
                        class="btn font-14-bold"
                        data-ng-click="modalOptions.close()">Close
                </button>
                <button style="background-color: #004065; color: #ffffff; width: 70px;" type="button" class="btn ng-binding" ng-disabled="modalOptions.okResult.heading.length <= 0 || modalOptions.okResult.subheading.length <=0" data-ng-click="modalOptions.ok()">OK</button>
            </div>
        </div>
    </div>
    `,
    styleUrls: ['./featured-search-dialog.component.scss']
    })
    export class FeaturedSearchDialogComponent {

    @Input() heading;
    @Input() subheading;

    constructor(public activeModal: NgbActiveModal) {}

    }

Custom Modal Service :

import { Injectable, Input, ComponentFactoryResolver } from '@angular/core';
import {NgbModal, NgbActiveModal} from '@ng-bootstrap/ng-bootstrap';
@Injectable()
export class ModalService {
    constructor(private ngbModal: NgbModal,
                private componentFactoryResolver: ComponentFactoryResolver) {}

  showDefaultModalComponent(theComponent: any, headerText: any, bodyText: any) {
    const componenetFactory = this.componentFactoryResolver.resolveComponentFactory(theComponent);
    const modalRef = this.ngbModal.open(theComponent);
    modalRef.componentInstance.bodyText = bodyText;
    modalRef.componentInstance.headerText = headerText;
    return modalRef;
  }

  showFeaturedDialog(theComponent: any, heading: any, subheading: any) {
    const componenetFactory = this.componentFactoryResolver.resolveComponentFactory(theComponent);
    const modalRef = this.ngbModal.open(theComponent);
    return modalRef;
  }


}
0
votes

To begin with: NgbModal, NgbActiveModal come from the package '@ng-bootstrap/ng-bootstrap'.

I think there's is no need for you to create a separate service as 'dynamic template' feature can be achieved by what's provided by the package itself. Let's see how:

Refer the image below(I guess that's the scenario). In your main component where you've put your 'default-modal', in my case it's -detail(folder), the modal(default-modal) is triggered from that component(-detail.component).

Let's say you are editing an event in *-detail.component by clicking a button. This click triggers 'default-modal' pop-up. Let's see this in the code.

*-.detail.component.html <button class="btn" (click)="editEvents(eventvalues)"> Edit </button>

*-detail.component.ts

editEvents(events) {
const activeModal = this.modalService.open(DefaultModal, { size: 'lg' });
activeModal.componentInstance.modalHeader = 'Edit Event';
activeModal.componentInstance.eventdata = events;  }

Now, the Modal Component: modal.component.html

<p>{{modalHeader}}</p>
<p> {{eventdata }} </p>

Note that you need to make necessary imports to your files. In component module import NgbModalModule also add to imports array. In component.ts file: NgbModal and import { DefaultModal } from './default-modal/default-modal.component';

enter image description here