5

The goal: to use components and not use $scope to set data. There isn't an error to share, the issue is that the data element isn't set when the dialog loads the component. The screen shot shows the current state of the dialog, there should be an object bound in tab #2 (Info). I can verify the the object (document) is available after the dialog loads using the onComplete event. I've tried to bind the data available to the dialog call to the component in the following ways below:

enter image description here

1 using locals:

  locals: {
         document: document     
  },
  bindToController: true,
  onComplete: function(){
                    console.log('document: %O', document);
  }

2 using bindings:

   bindings: {
         document: '='
    }

3 using resolve:

  resolve: {
              document: function() {
                          return document;
                        }
            }

The component:

I believe the error is here, the bindings, the "old way" used $scope vars so the bindings wired effortlessly.

(function(){
'use strict';
angular.module('adminClientApp')
.component('documentEdit', {
    templateUrl: 'js/app/components/document/documentEdit/document-edit.html',
    controller: function DocumentEditController($mdToast, $mdMedia) {
       var var documentEdit = this;
        documentEdit.document;

       },
       bindings: {
         document: '<'
       }
    });
  })();

the dialog call

the DialogController just has the $mdDialog events in it. I realize that the locals and bindToController are targeting the controller specified in the dialog (DialogController). I'm stumped here - how to set/pass/wire the document to the component controller?

   this.showEdit = function ($event, document) {
                var parentEl = angular.element(document.body);

                $mdDialog.show({
                            parent: parentEl,
                            targetEvent: $event,
                            template: '<div><document-edit document="documentEdit.document"></document-edit></div>',
                            resolve: {
                                       document: function(){ return document;}
                            },
                            controller: DialogController,
                            onComplete: function(){
                                console.log('document: %O', document);
                            }
                        });

        }
Splaktar
  • 5,506
  • 5
  • 43
  • 74
Will Lopez
  • 2,089
  • 3
  • 40
  • 64

2 Answers2

4

You don't show your DialogController, but there is probably an issue in there. I believe that you also need to give it a string when you give it a controller reference, e.g.

controller: 'DialogController',

See the below example which shows how to pass in values correctly using $mdDialog.

(function() {
  angular
    .module('exampleApp', ['ngAnimate', 'ngAria', 'ngMaterial'])
    .controller('ExampleController', ExampleController);

  function ExampleController($mdDialog) {
    var vm = this;
    vm.dialogTemplate = '<md-dialog><md-dialog-content><document-edit document="vm.document"></document-edit></md-dialog-content></md-dialog>';
    vm.document = {
      id: '11',
      name: 'test',
    };
    vm.showLocalsBindedDialog = function(event) {
      $mdDialog.show({
        template: vm.dialogTemplate,
        targetEvent: event,
        clickOutsideToClose: true,
        escapeToClose: true,
        controller: 'DocumentDialogCtrl',
        controllerAs: 'vm',
        bindToController: true,
        locals: {
          'document': vm.document
        }
      });
    }

    vm.showResolveBindedDialog = function(event) {
      $mdDialog.show({
        template: vm.dialogTemplate,
        targetEvent: event,
        clickOutsideToClose: true,
        escapeToClose: true,
        controller: 'DocumentDialogCtrl',
        controllerAs: 'vm',
        bindToController: true,
        resolve: {
          document: function() {
            return vm.document;
          }
        }
      });
    }
  }
  ExampleController.$inject = ['$mdDialog'];
})();

(function() {
  angular
    .module('exampleApp')
    .controller('DocumentDialogCtrl', DocumentDialogCtrl);

  function DocumentDialogCtrl(document) {
    var vm = this;
    vm.document = document;
  }
  DocumentDialogCtrl.$inject = ['document'];
})();

(function() {
  'use strict';
  angular.module('exampleApp')
    .component('documentEdit', {
      bindings: {
        document: '<'
      },
      template: '<p>ID:{{vm.document.id}}</p><p>NAME:{{vm.document.name}}</p>',
      controller: DocumentEditController,
      controllerAs: 'vm'
    });

  function DocumentEditController() {
    var vm = this;
  }
})();
<!DOCTYPE html>
<html ng-app='exampleApp'>

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular.min.js"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular-animate.min.js"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular-aria.min.js"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.0.9/angular-material.min.css">
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.0.9/angular-material.min.js"></script>
</head>

<body ng-controller="ExampleController as vm">
  <button ng-click="vm.showLocalsBindedDialog($event)">Show dialog with local passed in values</button>
  <button ng-click="vm.showResolveBindedDialog($event)">Show dialog with resolve passed in values</button>
</body>

</html>
ScottL
  • 1,755
  • 10
  • 7
  • 3
    This doesn't use components at all... Is the normal way to use a material dialog. – Vi100 Oct 24 '16 at 10:28
  • It uses the component documentEdit. Look at vm.dialogTemplate, i.e. the template passed to the dialog. The code example above is the way to do it for the scenario in the OP. See the [docs](https://material.angularjs.org/latest/api/service/$mdDialog) if you require more information on how to use material dialog. – ScottL Oct 26 '16 at 02:23
3

Another possibility is the is to use the scope option.

const tempScope = $rootScope.$new(true);
tempScope.document = document; // This is the local variable

$mdDialog.show({
    scope: tempScope // Give the scope to the dialog
    parent: parentEl,
    targetEvent: $event,
    template: '<document-edit document="document"></document-edit>', // Use scope
    onComplete: function() {
        console.log('document: %O', document);
    }
});

This will create a temporary scope for compiling the template. You still need to bind the data in the template (document="document"), but you can omit the intermediate controller.

Note that if you want to use the resolve to resolve promises, you need to do that manually before showing the dialog.

Bjarke Pjedsted
  • 542
  • 7
  • 10
  • Is there a way to bind output parameters to a component in $mdDialog? For instance, if I had an `onDocumentSubmitted: '&'` binding.. Or is `onComplete` the preferred method? I'm currently using `$scope.$on()` and `$scope.$emit()` to capture those sorts of events, but I'd like to remain consistent with other components by using output parameters. –  Jan 28 '17 at 20:02