5

working the first time with $mdDialog I am used to create a dialog with an external HTML Template.

So far, so good,... it works template can get opened, but ng-click in the html wont work anymore.

And I cannot find the reason for it.

The mdDialog gets called in userController like this:

<md-icon
        layout="row"
        flex md-font-set="material-icons"
        class="active"
        ng-click="vm.showMenu($event)">
    menu
</md-icon>

The method to open the $mdDialog in userController:

vm.showMenu = function showMenu(ev){

    $mdDialog.show({
        controller: MenuDialogController,
        templateUrl: 'app/components/head/user/menu.dialog.html',
        parent: angular.element($document.body),
        targetEvent: ev,
        clickOutsideToClose:true,
        fullscreen: $scope.customFullscreen // Only for -xs, -sm breakpoints.
    })
        .then(function(answer) {
            $scope.status = 'You said the information was "' + answer + '".';
        }, function() {
            $scope.status = 'You cancelled the dialog.';
        });
};

And this is the dialog controller for the dialog, where the buttons are not working:

angular
    .module('trax')
    .controller('MenuDialogController', MenuDialogController);

function MenuDialogController() {

    var vm = this;

    vm.close = function close(){
        alert('close clicked');
    }

    vm.ok = function ok(){
        alert('ok clicked');
    }

}

And this is the html code for the dialogController:

<md-dialog aria-label="User Menu">
    <form ng-cloak>
        <md-toolbar>
            <div class="md-toolbar-tools">
                <h2>User Menu</h2>
                <span flex></span>
                <md-button class="md-icon-button" ng-click="vm.close($event)">
                    <md-icon md-font-set="material-icons">close</md-icon>
                </md-button>
            </div>
        </md-toolbar>

        <md-dialog-content>
            <div class="md-dialog-content">
                <h2>Dialog Title</h2>
                <p>Dialog Text....</p>
                <p ng-click="vm.test($event)">test</p>
            </div>
        </md-dialog-content>

        <md-dialog-actions layout="row">
            <md-button href="http://en.wikipedia.org/wiki/Mango" target="_blank" md-autofocus>
                More on Wikipedia
            </md-button>
            <span flex></span>
            <md-button ng-click="vm.close($event)">
                cancel
            </md-button>
            <md-button ng-click="vm.ok($event)">
                ok
            </md-button>
        </md-dialog-actions>
    </form>
</md-dialog>

None of the ng-clicks is working!

Any hint for me?

idmean
  • 14,540
  • 9
  • 54
  • 83
n00n
  • 654
  • 1
  • 10
  • 30
  • Can you add these files as code snippets instead? It will help instead of making others have to go to that specific URL to see your code. Please also use the tag [tag:angularjs-material] instead of the tag [tag:angular-material] – Edric Nov 06 '17 at 13:04
  • can you please create a demo project on plunker? – Vishal Nov 12 '17 at 13:44
  • Hi, can you show your routeConfiguration? – Sunil Lama Nov 15 '17 at 10:43
  • 1
    I suspect this is because you have your ng-clicks binded to something called `vm`, but `vm` doesn't exist in your `MenuDialogController`'s scope, because you haven't passed in `controllerAs: 'vm'` to the `$mdDialog.show` line. See this - https://github.com/angular/material/issues/4374 – Jon La Marr Nov 15 '17 at 21:32
  • @JonLaMarr suggestion should solve the problem. – scipper Nov 17 '17 at 10:58
  • @n00n Let me know if you want me to add it as an answer so more people can see it. – Jon La Marr Nov 17 '17 at 16:42

3 Answers3

2

To leave your code unmodified you have to add after

var vm = this;

with

var vm = this;
$scope.vm = vm;

In this way you can use it in your template.

Another way is declare the methods directly in $scope as

$scope.close = function() { ... };
$scope.ok = function() { ... };

The first method is equal to declare controllerAs: "vm" in $mdDialog.show helper method

Matteo Gaggiano
  • 1,254
  • 15
  • 28
1
    angular
    .module('trax')
    .controller('MenuDialogController', MenuDialogController);

function MenuDialogController() {

    var vm = this;

    //Here change vm to $scope
    $scope.close = function close(){
        alert('close clicked');
    }

    $scope.ok = function ok(){
        alert('ok clicked');
    }

}

You have to assign your funcs to the $scope of your dialog controller

Hey24sheep
  • 1,172
  • 6
  • 16
  • OKI, this works, but the event gets implemented like this: ng-click="close($event)" wouldnt it be better if it is something like ng-click="ctrl.close($event)"? And how to close the dialog again? In scope of my controller this.hide() does not work – n00n Nov 21 '17 at 20:31
  • But I get an Error on $scope.close = function close (){ ... } This is the error... You should not set properties on $scope in controllers. Use controllerAs syntax and add data to "this" – n00n Nov 22 '17 at 19:51
  • There is no error like that. It personal choice which one you want to use. Controller as or direct scope. So just use which you like. – Hey24sheep Nov 23 '17 at 03:09
1

It appears thet your setup it slightly off. In fact, it seems to be that you wish to pass the scope into this dialog. Taken from the examples at the $mdDialog docs I was able to find the following...

// Dialog #3 - Demonstrate use of ControllerAs and passing $scope to dialog
//             Here we used ng-controller="GreetingController as vm" and
//             $scope.vm === <controller instance="">

It looks like you'll need to modify your implementation to match this pattern. Try the following...

$mdDialog.show({
  controller: MenuDialogController,
  templateUrl: 'app/components/head/user/menu.dialog.html',
  parent: angular.element($document.body),
  targetEvent: ev,
  clickOutsideToClose:true,
  fullscreen: $scope.customFullscreen,
  scope: $scope,         // use parent scope in template
  preserveScope: true,   // do not forget this if use parent scope
}).then(function(answer) {
  $scope.status = 'You said the information was "' + answer + '".';
}, function() {
  $scope.status = 'You cancelled the dialog.';
});

Notice the scope and preserveScope options specified.

// Since MenuDialogController is instantiated with ControllerAs syntax
// AND we are passing the parent '$scope' to the dialog, we MUST
// use 'vm.<xxx>' in the template markup
scniro
  • 16,844
  • 8
  • 62
  • 106
  • I saw it, too. But how to let the promise get fired in my MenuDialogController? Firing an event on scope / root scope to watch it in MenuDialogController? – n00n Nov 13 '17 at 08:02
  • I am unsure. However, if you can provide a [plunker](https://plnkr.co/) which reproduce your issue, I'll gladly help you solve it. – scniro Nov 13 '17 at 13:22
  • thx. it is working, .. but my unit tests fail as explained above. – n00n Nov 22 '17 at 21:08
  • @n00n I am not seeing any unit test nor mention of in your question – scniro Nov 22 '17 at 22:17
  • Sorry, not the unit tests, lint testing does the error. On gulp build / serve it gives me this error: – n00n Nov 23 '17 at 21:11
  • ...PS P:\projects\trax> gulp serve [22:12:41] Using gulpfile P:\projects\trax\gulpfile.js ... ... [22:12:52] Finished 'styles' after 7.1 s 10:5 error You should not set properties on $scope in controllers. Use controllerAs syntax and add data to "this" angular/controller-as 14:5 error You should not set properties on $scope in controllers. Use controllerAs syntax and add data to "this" angular/controller-as 18:5 error You should not set properties on $scope in controllers. Use controllerAs syntax and add data to "this" angular/controller-as – n00n Nov 23 '17 at 21:14
  • You didn't mention anything about linting either. If it works, why not accept the answer and solve the lint warnings after the fact? – scniro Nov 26 '17 at 21:53