-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(modal): add modals service to launch modal components #579
Comments
@kokokenada I fixed your plnkr as far as I could, but the plnkr does not open up: https://plnkr.co/edit/DpxOudhAzuPwEZz0xdcR?p=preview Any idea why? |
@jhiemer , thanks for looking at it. I took your config and got further in my plunker. It's still crashes with the dreaded "TypeError: Cannot read property 'query' of null". (I groan every time I get this because it's so hard to find the problem...) Anyways, I'll keep at it. I've also push my hobby app to github which has the dialog service running. https://github.com/kokokenada/for-real-cards Re your instance, when I looked at the console log, I got:
|
OK, the app comes up now. (https://plnkr.co/edit/Cua6HJYrN3i2SkgC0iLj?p=preview). I had to comment out a critical piece, so the "Open" button doesn't work. Have a look at the constructor of the modal-outlet.component.ts. Putting the injected services back in causes the app not to run. Any idea why this doesn't work in plunker? (Works fine in my app.) |
@kokokenada take a look here, I think I managed to get it running: https://plnkr.co/edit/SC3m12oquQ3mNRtTi1IH?p=preview What you have struggled with in the constructor (happened to me as well) is the missing constructor(@Inject(ViewContainerRef) private vcRef: ViewContainerRef,
@Inject(ComponentResolver) private resolver: ComponentResolver) {
}
@valorkin do you think this is something one could add to ng2-bootstrap? This is nearly that what I have asked for in: #29 (comment) |
Thanks for the fixes @jhiemer ! @valorkin , It think something like this is necessary in order to follow the style guide's (https://angular.io/docs/ts/latest/guide/style-guide.html) requirement of "single responsibility". Otherwise, how do you isolate the modal's implementation from the caller's implementation? How do you call the same modal from multiple locations? Also, just to connect the dots: shlomiassaf/ngx-modialog#104 (was the twbs modal a fork from that? - I thought I noticed some similarities....) If there is interest in this approach, one aspect I didn't like about the proof of concept implementation is cramming all of the parameters in one single @input named componentParameters and forcing users to break it up with ngOnChanges. My first implementation tried to translate the top level keys into individual@input's but I hit a snag. (I was generating the HTML by stringifying the values and angular complained when an array was >10. (!)) (http://stackoverflow.com/questions/37113385/unsupported-number-of-argument-for-pure-functions) And that was just the first problem. Not sure how to dynamically define @inputs... |
@kokokenada regarding the componentParameters: if I remember correctly it was nearly the same as in the Angular 1 implementation. You had the ability to use the config parameter, which provided all options, including data to be transferred to the modal. Although I don't know if there is any better option in Angular 2, this seems a valid way to go on from. |
@jhiemer hey, I have invited you to ng2-team, I see you are helping a lot to guys issues |
@valorkin thanks, saw it. What do you think, how should we proceed with the service based modal implementation? @kokokenada could you create a pull-request, that we could work on the implementation? |
@jhiemer I need to some test for modals before creating service >.< |
Also, would be great to append modal at body by service. I have z-index issue with current modal implementation. |
+1 |
I have used this modal window service but it is not working in my rc.5 project. it gives warning for PromiseResolver saying that it is deprecated in rc.5. so what should i use instead of PromiseResolver to run in rc5 |
Hi everyone, in my team, we manage to get something working like that : We create a generic component that take care of the dynamic component creation : import { Subscription } from 'rxjs/Rx';
import { ModalDirective } from 'ng2-bootstrap/ng2-bootstrap';
import { Component, OnInit, ViewChild, ViewContainerRef, ComponentFactoryResolver, ReflectiveInjector, EventEmitter, Output } from '@angular/core';
export class ComponentData {
public component: any;
public inputs?: any;
public settings?: any;
}
@Component({
selector: 'dynamic-modal',
entryComponents: [],
template: `<div bsModal #dynamicModal="bs-modal" class="modal fade" role="dialog" aria-hidden="true"><div #dynamicComponentContainer></div></div>`,
})
export class DynamicModalComponent implements OnInit {
@Output() dynamicModalComponent = new EventEmitter<DynamicModalComponent>();
@ViewChild('dynamicModal') dynamicModal: ModalDirective;
@ViewChild('dynamicComponentContainer', { read: ViewContainerRef }) dynamicComponentContainer: ViewContainerRef;
private modalSubscriptions: Subscription[] = [];
private modalSettings: any;
constructor(private resolver: ComponentFactoryResolver) { }
ngOnInit() {
this.dynamicModalComponent.emit(this);
}
public showModal(modal: ComponentData) {
// Inputs need to be in the following format to be resolved properly
modal.inputs = modal.inputs || {};
this.modalSettings = modal.settings;
let inputProviders = Object.keys(modal.inputs).map((inputName) => { return { provide: inputName, useValue: modal.inputs[inputName] }; });
let resolvedInputs = ReflectiveInjector.resolve(inputProviders);
let injector = ReflectiveInjector.fromResolvedProviders(resolvedInputs, this.dynamicComponentContainer.parentInjector);
let factory = this.resolver.resolveComponentFactory(modal.component);
let componentCreated = factory.create(injector);
this.dynamicComponentContainer.clear();
this.dynamicComponentContainer.insert(componentCreated.hostView);
this.dynamicModal.show();
}
public hideModal() {
this.dynamicModal.hide();
}
public onShown(action: () => void) {
this.modalSubscriptions.push(this.dynamicModal.onShown.subscribe(action));
}
public onHidden(action: () => void) {
this.modalSubscriptions.push(this.dynamicModal.onHidden.subscribe(() => {
action();
this.clearSubscriptions();
}));
}
public getModalSettings() {
return this.modalSettings;
}
private clearSubscriptions() {
this.modalSubscriptions.map(sub => { sub.unsubscribe(); });
this.modalSubscriptions = [];
}
} Then we use a shared service to expose methods to manage a modal and take care of the current opened modal : import { ModalOptions } from 'ng2-bootstrap/ng2-bootstrap';
import { ComponentData, DynamicModalComponent } from './../components/dynamicModal/dynamicModal.component';
import { Injectable } from '@angular/core';
@Injectable()
export class ModalService {
private dynamicModalComponent: DynamicModalComponent;
public initializeDynamicModal(dynModal: DynamicModalComponent) {
this.dynamicModalComponent = dynModal;
}
public configureModal(config: ModalOptions) {
this.dynamicModalComponent.dynamicModal.config = config;
}
public getModalSettings() {
return this.dynamicModalComponent.getModalSettings();
}
public showModal(modal: ComponentData) {
this.dynamicModalComponent.showModal(modal);
}
public hideModal() {
this.dynamicModalComponent.hideModal();
}
public onShown(action: () => void) {
this.dynamicModalComponent.onShown(action);
}
public onHidden(action: () => void) {
let hidden = this.dynamicModalComponent.onHidden(action);
}
} And we have to bootstrap that dynamic component in the App root component like this : <dynamic-modal (dynamicModalComponent)="onDynamicModalLoaded($event)"></dynamic-modal>
<div>
<main>
<router-outlet></router-outlet>
</main>
</div> App.component.ts: ...
private onDynamicModalLoaded(event) {
this.modalService.initializeDynamicModal(event);
}
... Then we just have to use this by creating a basic component that contain a modal as template and use it like that : this.modalService.showModal({ component: **yourBodyModalComponent**, settings: { **some useful parameters for your component** } }); Hope thats could help ! |
@vieillecam not sure if there's a better way, but I had to also add the following to the module declaration to avoid an error ( ...
entryComponents: [
*** yourBodyModalComponent***
],
... and use an injector to pull the inputs: ...
@Input() model: MyModel;
ngOnInit() {
let tempModel = this.injector.get('model', null);
if (tempModel) {
this.model = tempModel;
}
}
... I was using lazy loading for modules, so I also needed to pass through the public showModal(modal: ComponentData, parentInjector?: Injector) {
parentInjector = parentInjector || this.dynamicComponentContainer.parentInjector;
let resolver = parentInjector.get(ComponentFactoryResolver) || this.resolver;
// Inputs need to be in the following format to be resolved properly
modal.inputs = modal.inputs || {};
this.modalSettings = modal.settings;
let inputProviders = Object.keys(modal.inputs).map((inputName) => {
return {provide: inputName, useValue: modal.inputs[inputName]};
});
let resolvedInputs = ReflectiveInjector.resolve(inputProviders);
let injector = ReflectiveInjector.fromResolvedProviders(resolvedInputs, parentInjector);
let factory = resolver.resolveComponentFactory(modal.component);
let componentCreated = factory.create(injector);
this.dynamicComponentContainer.clear();
this.dynamicComponentContainer.insert(componentCreated.hostView);
this.dynamicModal.show();
} and then the following in the calling module: ...
constructor(private modalService: ModalService, private injector: Injector) {
}
...
this.modalService.showModal({
component: TestComponent,
inputs: {
model: ...
}
}, this.injector);
... |
@vieillecam how can i close the modal from dynamic modal itself ? |
@vieillecam okay got it, just need to inject the |
@valorkin , According to answers from other related items to the ModalService , at the end of January it was planned to start implementing the current feature.
|
Just update: (ngx-home.slack.com discussion fragment ) A: Dmitriy Shekhovtsov [May, 13th, 2017 4:57 PM] |
Another STATUS Update: Dmitriy Shekhovtsov [7:29 PM] |
Work in progress #2047 |
fixes #1998 fixes #1995 fixes #1830 fixes #1181 fixes #579 * feat(modal): modal service wip * feat(modal): wip, add close buttons attribute support, add ability to open modaol with component * feat(modal): add config, move creating of loader to constructor, add demo * fix(modal): fix service path * fix(modal): fix api-docs * fix(modal): fix scroll on modals created by service, add docs * feat(modal): wip, add BsModalService.show output obj * refactor(modal): change inner component getter * feat(modal): add BsModalRef and docs * feat(modal): remove data-attributes, return BsModalRef, update docs * feat(modal): add docs for BsModalService, BsModalRef, update demo * feat(modal): add bs4 support * feat(modal): keep focus inside a modal * chore(modals): small refactoring (#2128) * chore(modals): simplify service (#2130) * chore(modal): view container ref made optional for component loader (#2133) * fix(modal): fix backdrop flickering * fix(modal): fix backdrop click on the left/right sides, add class option * feat(modals): nested modals wip * fix(modal): fix multiple hide() call * fix(modal): fix multiple backdrop clicks, fix padding * fix(modal): fixed padding * fix(modal): fix page flickering * feat(modal): add isAnimated support, add service section to demo * fix(test): fix popover and tyepahead unit tests
any one please help this to work in angular4 plnkr is now in angular2 |
@arunalexp Take a look at this modal module proof of concept project I created for my team using angular 5. |
https://stackoverflow.com/questions/46408428/ngx-bootstrap-modal-how-to-get-a-return-value-from-a-modal/48803705#48803705 |
I'd like to launch a modal via a service like you could in angular 1. I've create a proof of concept in plunker. https://plnkr.co/edit/Cua6HJYrN3i2SkgC0iLj?p=preview
It's running on my machine, but plunker can't resolve rxjs and I wasn't able to figure it our quickly, so help appreciated.
The text was updated successfully, but these errors were encountered: