Skip to content
This repository has been archived by the owner on Dec 1, 2023. It is now read-only.

Instantiate controller when opening modal #728

Closed
garrettheel opened this issue Apr 29, 2014 · 19 comments
Closed

Instantiate controller when opening modal #728

garrettheel opened this issue Apr 29, 2014 · 19 comments

Comments

@garrettheel
Copy link

Feature request - be able to pass in a Controller when programmatically creating modals. This is a nice way to pass in data to the modal that angular-ui also allows.

Example:

var data = {x: 1};
$modal({
  template: 'SomeModal.html',
  controller: 'MyModalController',
  resolve: {  // this is how angular-ui does it
    data: function() { return data; }
  }
});

// ...

myApp.controller('MyModalController', function(data) {
  console.log('x = '  + data.x);
});

Another benefit of this over the current approach is that it allows instantiating the Controller when the modal is created rather than at page load.

If angularstrap already supports this but I've missed it somewhere please let me know, otherwise I'm happy to have a crack at implementing if you think it's a good idea.

@evillemez
Copy link

Yeah, this is something I'm trying to do as well. You can use ng-controller inside the modal template, and pass it a custom created scope, though.

I eventually factored it out into a service that wraps the $modal service and manages creating/destroying the custom scopes on show/close.

@rodrigoreis22
Copy link

👍 I'd like to have this feature here as well. I'm only using angular-ui $modal now because they support this separated controller for modals.

@evillemez can you share your solution?

@evillemez
Copy link

@rodrigoreis22 Sure thing. I put the implementation in a gist, please excuse the CoffeeScript if that's not your thing. :)

https://gist.github.com/evillemez/ef89eb7be58de098d6a0

In our app, we have various modals that can be triggered from multiple places within the app. So, we have a provider for defining what the modal is, along with default configuration for AngularStrap's $modal service. The provider builds a service that can launch the modal, and pass along any data it needs to the modal's scope. The gist includes usage examples, and the provider definition.

@rodrigoreis22
Copy link

Thanks @evillemez

@pswai
Copy link

pswai commented Jan 3, 2015

Not sure if there is any progress on this, but I have decorated $modal to include a new method named open to behave like $modal.open() in UI Bootstrap. It adds controller, controllerAs and resolve options. I have created a gist for it:

https://gist.github.com/pswai/c8dd1c3ef8f3f04a02e7

@pswai
Copy link

pswai commented Jan 3, 2015

In case you do not use lodash/underscore.js (you should consider), I have created a gist for it too:

https://gist.github.com/pswai/359102cea1f251542eda

@psi-4ward
Copy link

+1

1 similar comment
@richardm
Copy link

richardm commented Jan 7, 2015

+1

@stgunholy
Copy link

As long as more and more people migrating from bootstrap-ui this feature can come up really handy.

@cef62
Copy link

cef62 commented Mar 17, 2015

+1 @pswai great job! I've extended your gist adding some features.
https://gist.github.com/cef62/0f8ea91e3b0be8f87c24

@lukasz-karolewski
Copy link

+1 this is very important feature as it encourages better separation of concerns, also resolve allow easy way of passing data into modal controller.

@gaui
Copy link

gaui commented May 14, 2015

+1 I am shocked that this isn't possible. Logic in modals can be very complex, so they need a seperate controller. Having all your modal logic in your main controller, is very bad. Controllers and resolve are both available in Angular-UI. This makes modal architecture in Angular-UI better.

@TrevorPage
Copy link

+1.

I understand how to have a separate scope for the modal, but the only way I know to assign a dedicated controller for the modal is by ng-controller in the template used for the modal. My current situation is that I would like to use the same HTML template for both an "add" modal and an "edit" modal, which means that when my service creates the modal, it should create either an "addWidgetController" or "editWidgetController" as appropriate. As things stand, I will need to combine the functionality for 'add' and 'edit' into one controller.

@pswai's solution looks interesting (thanks for posting this). It would be nice to only rely on standard functionality in the library, however.

@mgcrea
Copy link
Owner

mgcrea commented Jun 22, 2015

I think the proper way to do this would be to use a global compiler helper that would support a broad range of options. Something like Angular Material's compiler.js.

I'm more than open to PR's providing this feature.

@TrevorPage
Copy link

Unfortunately I think I'm too inexperienced with Angular / JS to provide PRs for the library itself, but I thought I'd share something that just worked for me in case anyone finds it useful in the meantime.

My scenario is that I use a service to open a modal. The purpose of the service is to provide a promise-like interface (taken from a Plunker that @mgcrea provided) as well as creating the custom scope. A dedicated .html template is used with the modal. It is necessary to use one of two possible controllers, chosen based on parameter(s) passed when opening the modal.

Controller declaration in my html template is:

<div ng-controller="getController">
    <div class="modal-header">
....

The service:

.service('MyModalService', function ($modal, $rootScope, $q, $controller) {

    // AngularJS will instantiate a singleton by calling "new" on this function

    /**
     * Show the widget add dialogue. 
     * @return A promise which is resolved with no arguments when dialogue is closed.
     */
    this.showAdd = function() {

        var deferred = $q.defer();

        // We provide a dedicated non-inherited scope for the modal. It's used to convey
        // argument(s) into the modal (we don't use any for this modal) and to register result callback(s).
        var modalScope = $rootScope.$new();      

        modalScope.getController = function(){ 
            return $controller('WidgetAddModalCtrl', { 
                $scope: modalScope }); 
            };

        // Callback for modal controller to call when finished
        modalScope.modalFinished = function() {
            // Angular strap $modal() return value also has a $promise which should be
            // used for show/hide apparently, as it ensures template is ready.
            addModal.$promise.then(addModal.hide);
            deferred.resolve();
        };

        var addModal = $modal({
            title: 'Title', 
            contentTemplate: 'app/WidgetModal/WidgetModal.html', 
            scope: modalScope, 
            show: true,
            backdrop: 'static'
        });

        return deferred.promise;
    };

    /**
     * Show the widget edit dialogue. 
     * @return A promise which is resolved with no arguments when dialogue is closed.
     */
    this.showEdit = function() {

        var deferred = $q.defer();

        // We provide a dedicated non-inherited scope for the modal. It's used to convey
        // argument(s) into the modal (we don't use any for this modal) and to register result callback(s).
        var modalScope = $rootScope.$new();      

        modalScope.getController = function(){ 
            return $controller('WidgetEditModalCtrl', { 
                $scope: modalScope }); 
            };

        // Callback for modal controller to call when finished
        modalScope.modalFinished = function() {
            // Angular strap $modal() return value also has a $promise which should be
            // used for show/hide apparently, as it ensures template is ready.
            addModal.$promise.then(addModal.hide);
            deferred.resolve();
        };

        var addModal = $modal({
            title: 'Title', 
            contentTemplate: 'app/WidgetModal/WidgetModal.html', 
            scope: modalScope, 
            show: true,
            backdrop: 'static'
        });

        return deferred.promise;
    };        


});

With the above solution, with the service injected into a controller, either editModal or addModal can be called to show a modal for editing or adding a widget. In either case, the service takes care of providing a dedicated $scope to the modal. Also in either case the same html template is used. However, the actual controller used is either WidgetEditModalCtrl or WidgetAddModalCtrl.

I realise there is lots of duplication in the service code -- I will probably edit this a few times as I refine it.

@gaui
Copy link

gaui commented Jun 22, 2015

Take a look at this project. This is a similiar behavior like in UI-bootstrap. You control controllers, input, what happens before modal, after, etc. Much more control.

@mgcrea mgcrea closed this as completed in 8e54db8 Jul 12, 2015
mgcrea added a commit that referenced this issue Jul 12, 2015
…or `controller`, `controllerAs`, `template`, `templateUrl` options (fixes #732, fixes #728, fixes #1394, fixes #1735)
mgcrea added a commit that referenced this issue Jul 12, 2015
…or `controller`, `controllerAs`, `template`, `templateUrl` options (fixes #732, fixes #728, fixes #1394, fixes #1735)
@mgcrea
Copy link
Owner

mgcrea commented Jul 12, 2015

Finally took the time to backport the compiler from angular-material's project. You can now use controller, controllerAs, templateUrl and template options in your modal and derivatives. Hope it solves most of the issues you encountered with AngularStrap's modals.

@TrevorPage
Copy link

Thanks @mgcrea that's fantastic.

@lock
Copy link

lock bot commented Jan 26, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot added the outdated label Jan 26, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Jan 26, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests