Material: mdPanel issue after minification.

Created on 4 Jul 2016  Â·  34Comments  Â·  Source: angular/material

Actual Behavior:

  • What is the issue? mdPanel stops working after minfying code. I have a grunt task that minifies my files and groups bower libraries into single js files. Before this process mdPanel works fine but afterwards i get an error in the vendor.js file. I use mdDialog (and many other material services) in my code and they work fine after this process.

I get the following error: [$injector:unpr] Unknown provider: aProvider <- a (in my vendor.js file)

The error occurs here: (in the function... f.apply(b, a)
this.$get = ["$window", function(c) { function e(a) { return a instanceof Error && (a.stack ? a = a.message && -1 === a.stack.indexOf(a.message) ? "Error: " + a.message + "\n" + a.stack : a.stack : a.sourceURL && (a = a.message + "\n" + a.sourceURL + ":" + a.line)), a } function f(a) { var b = c.console || {} , f = b[a] || b.log || n , g = !1; try { g = !!f.apply } catch (h) {} return g ? function() { var a = []; return d(arguments, function(b) { a.push(e(b)) }), f.apply(b, a) } : function(a, b) { f(a, null == b ? "" : b) } }

  • What is the expected behavior? mdPanel should work correctly after minifying / grouping.

CodePen (or steps to reproduce the issue): *

  • CodePen Demo which shows your issue:
  • Details:

Angular Versions: *

  • Angular Version:1.5
  • Angular Material Version:1.1.0 RC5

Additional Information:

  • Browser Type: *Chrome

Shortcut to create a new CodePen Demo.
Note: * indicates required information. Without this information, your issue may be auto-closed.

Do not modify the titles or questions. Simply add your responses to the ends of the questions.
Add more lines if needed.

- Lots of Comments nice to have works as expected

Most helpful comment

Thanks @oemmes

Yep I managed to get it sorted in the service by following the correct inject structure
e.g.

var controller = ['mdPanelRef', function (mdPanelRef) {
}]

I also do this for all my dialogs. ng-annotate doesn't show any errors but it's never worked for me on explicitly doing the $inject for my dialog controllers etc. I guess it's better practice to explicitly $inject myself then rely on ng-annotate.

All 34 comments

What does the code look like where you open the panel, or can you provide the code in a codepen? Are you doing dependency injection properly?

This is how i call the panel:

   var position = $mdPanel.newPanelPosition()

                .center();

                var config = {
                    attachTo: angular.element(document.body),
                    templateUrl: 'app/casesearch/dialogs/queryPanel.html',
                    controller: PanelMenuCtrl,
                    controllerAs: 'queryPanel',
                    position: position,
                    openFrom: ev,
                    clickOutsideToClose: true,
                    escapeToClose: true,
                    focusOnOpen: false,
                    fullscreen: false,
                    locals: {
                        theme: $scope.theme,
                        CurrentCase: $scope.CurrentCase
                    },
                };

                $mdPanel.open(config);

Before building this works fine..

I also noticed that
var position = $mdPanel.newPanelPosition() actually works when built so i would assume that my dependency injection is working.

Just in case my dependency injection looks like this:

 static $inject = ["$scope", "$rootScope", "$state", "$stateParams", "elasticservice", "$mdDialog", "devicetypes", "casequeries", "Auth", "$q", "$mdToast", "$mdColors", "$mdPanel"];

        constructor($scope, $rootScope, $state, $stateParams, elasticservice, $mdDialog, devicetypes, casequeries, Auth, $q, $mdToast, $mdColors, $mdPanel) {

Thanks

The easiest solution is to add ng-annotate task to your grunt build before the minification task

ofirmgr: I already do that:

 grunt.registerTask('build', [
    'clean:dist',
    'concurrent:pre',
    'concurrent:dist',
    'injector',
    'wiredep:client',
    'useminPrepare',
    'postcss',
    'ngtemplates',
    'concat',
    'ngAnnotate',
    'copy:dist',
    'babel:server',
    'cdnify',
    'cssmin',
    'uglify',
    'filerev',
    'usemin'
  ]);

I am just trying to figure out why all of the other angular material services work fine apart from mdPanel.

Thanks

I am using mdPanel as an advanced dropdown menu with sticky headers etc, when somone clicks an option it just sends the selected value back to the main controller.. Since mdDialog doesnt have any issues with my build process can mdDialog be used as a replacement? I have only used it so far for alerts so not quite sure if it can handle a custom drop down menu. Thanks EDIT I got mdMenu to do / look the same so i will stick with that.

hey @whittssg did u got any solution I have the same problem but with mdDialog...

Hi @eduardosanzb, i never did figure it out. I ended up modifying mdmenu to do what i was trying to do with mdpanel. The funny thing was that mdpanel would initialize and i could access it but there were just certain things i couldnt do with it (like sets it position) without it giving me the error (once minified). For all other things i ended up using jsPanel since mdpanel was the only thing i couldnt get working with material (mdDialog also worked fine for me).

Any work around on this? Getting after minification as well. Also using ngAnnotate during grunt build.

@apat183 I have added this to my current task list and hope to address it asap. Please check back soon.

Awesome @bradrich, let me know if I can provide anything in addition to what @whittssg provided above.

@whittssg What grunt minification library were you using?

If it helps, for me I've tried the following grunt-contrib-uglify versions:

  • 2.0.0
  • 0.11.1
  • 0.7.0

and the error points to this part of the code, hard to tell with minification:

MdPanelRef.prototype._createPanel = function() {
  var self = this;

  return this._$q(function(resolve, reject) {
    if (!self.config.locals) {
      self.config.locals = {};
    }

    self.config.locals.mdPanelRef = self;
    self._$mdCompiler.compile(self.config)
        .then(function(compileData) {
          self._panelContainer = compileData.link(self.config['scope']);
          getElement(self.config['attachTo']).append(self._panelContainer);

          if (self.config['disableParentScroll']) {
            self._restoreScroll = self._$mdUtil.disableScrollAround(
              null,
              self._panelContainer,
              { disableScrollMask: true }
            );
          }

          self._panelEl = angular.element(
              self._panelContainer[0].querySelector('.md-panel'));

          // Add a custom CSS class to the panel element.
          if (self.config['panelClass']) {
            self._panelEl.addClass(self.config['panelClass']);
          }

          // Handle click and touch events for the panel container.
          if (self.config['propagateContainerEvents']) {
            self._panelContainer.css('pointer-events', 'none');
          }

          // Panel may be outside the $rootElement, tell ngAnimate to animate
          // regardless.
          if (self._$animate.pin) {
            self._$animate.pin(self._panelContainer,
                getElement(self.config['attachTo']));
          }

          self._configureTrapFocus();
          self._addStyles().then(function() {
            resolve(self);
          }, reject);
        }, reject);
  });
};

@apat183 Thanks very much for this information. It is greatly appreciated.

@bradrich - try this: replace string index to direct references. e.g.

self.config.scope instead of self.config['scope'] in the panel.js

@ThomasBurleson Thank you for this info. I will attempt it this evening. I still haven't been able to get in front of my computer.

@apat183 - Do you have some special configuration for the uglify plugin? Would be helpful if you share your gruntfile per Github Gist or something else. Thanks in advance.

Here you go,

I'm using the panel as a onboarding walkthrough. Here is how I"m using it and the grunt file and package.json etc.

All I'm doing is grunt build.

https://github.com/apat183/Panel-minification-error

let me know what else I can add to repo. I can also provide the minification vendor file if that helps.

Thanks @apat183 for those detailed information. - You are awesome!

@apat183 Outstanding! Running tests now.

@apat183 Can you include your bower.json file? Can't run grunt build with it missing.

Added

@apat183 There should be an index.html file as well.

Added, I removed all the references to my internal scripts and just let bower, is that alright?

@apat183 That is correct.

@apat183 I got your project installed and built. There does seem to be two errors that are in the minified vendor.js file. One is an $injector error but does not point to anything Angular Material related. The other is an error that points to a function call within md-data-table. That is not a part of the Angular Material project.

I am not sure if there is something that I have missed. When you look at the console within your browser (assuming you are using Chrome), you should be able to click on the source of the error. When Chrome takes you to the spot within the minified source, there is a button at the bottom-left-hand corner that looks like this: {}. Clicking it will prettify the source and give you a better idea of where the issue came from. Can you take a look at that and see if it is different that what I have described above?

@bradrich I just re-added my mdpanel code to my project to see if i could get the source error for you. I built the app (with uglify and minify) as i was doing before and now i do not get an error when calling the panel. I was previously getting the error on RC5 but I have since upgraded my project to 1.1 but i never thought about testing mdpanel again. Thanks

ok Thanks for that.

Here is the error I'm getting straight from chrome.

vendor.31fcb47b.js:formatted:7595Error: [$injector:unpr] Unknown provider: aProvider <- a
http://errors.angularjs.org/1.5.6/$injector/unpr?p0=aProvider%20%3C-%20a
    at vendor.31fcb47b.js:formatted:4088
    at vendor.31fcb47b.js:formatted:5296
    at Object.d [as get] (vendor.31fcb47b.js:formatted:5235)
    at vendor.31fcb47b.js:formatted:5300
    at d (vendor.31fcb47b.js:formatted:5235)
    at e (vendor.31fcb47b.js:formatted:5248)
    at Object.g [as invoke] (vendor.31fcb47b.js:formatted:5258)
    at j.instance (vendor.31fcb47b.js:formatted:6748)
    at Object.link (vendor.31fcb47b.js:formatted:17774)
    at vendor.31fcb47b.js:formatted:22993(anonymous function) @ vendor.31fcb47b.js:formatted:7595(anonymous function) @ vendor.31fcb47b.js:formatted:6773g @ vendor.31fcb47b.js:formatted:8013(anonymous function) @ vendor.31fcb47b.js:formatted:8020$eval @ vendor.31fcb47b.js:formatted:8499$digest @ vendor.31fcb47b.js:formatted:8427$apply @ vendor.31fcb47b.js:formatted:8526i @ vendor.31fcb47b.js:formatted:7014u @ vendor.31fcb47b.js:formatted:7112x.onload @ vendor.31fcb47b.js:formatted:7139

Sorry I thought it was Angualr material because when I click the vendor.31fcb47b.js:formatted:22993(anonymous function) @ it would take me to line - a._panelContainer = e.link(a.config.scope), from below

        d.prototype._createPanel = function() {
            var a = this;
            return this._$q(function(c, d) {
                a.config.locals || (a.config.locals = {}),
                a.config.locals.mdPanelRef = a,
                a._$mdCompiler.compile(a.config).then(function(e) {
                    a._panelContainer = e.link(a.config.scope),
                    g(a.config.attachTo).append(a._panelContainer),
                    a.config.disableParentScroll && (a._restoreScroll = a._$mdUtil.disableScrollAround(null , a._panelContainer, {
                        disableScrollMask: !0
                    })),
                    a._panelEl = b.element(a._panelContainer[0].querySelector(".md-panel")),
                    a.config.panelClass && a._panelEl.addClass(a.config.panelClass),
                    a.config.propagateContainerEvents && a._panelContainer.css("pointer-events", "none"),
                    a._$animate.pin && a._$animate.pin(a._panelContainer, g(a.config.attachTo)),
                    a._configureTrapFocus(),
                    a._addStyles().then(function() {
                        c(a)
                    }, d)
                }, d)
            })
        }

image

If I click the right hand error reference (in chrome debug console) it takes me to angular error
Also included formatted error. it's pointing to f.apply(b,a).

    function _b() {
        var a = !0
          , b = this;
        this.debugEnabled = function(b) {
            return s(b) ? (a = b,
            this) : a
        }
        ,
        this.$get = ["$window", function(c) {
            function e(a) {
                return a instanceof Error && (a.stack ? a = a.message && -1 === a.stack.indexOf(a.message) ? "Error: " + a.message + "\n" + a.stack : a.stack : a.sourceURL && (a = a.message + "\n" + a.sourceURL + ":" + a.line)),
                a
            }
            function f(a) {
                var b = c.console || {}
                  , f = b[a] || b.log || n
                  , g = !1;
                try {
                    g = !!f.apply
                } catch (h) {}
                return g ? function() {
                    var a = [];
                    return d(arguments, function(b) {
                        a.push(e(b))
                    }),
                    f.apply(b, a)
                }
                : function(a, b) {
                    f(a, null == b ? "" : b)
                }
            }
            return {
                log: f("log"),
                info: f("info"),
                warn: f("warn"),
                error: f("error"),
                debug: function() {
                    var c = f("debug");
                    return function() {
                        a && c.apply(b, arguments)
                    }
                }()
            }
        }
        ]
    }

image

If it helps I have a test environment online that I can provide you access to and you get reproduce the error but if you saying it's not angular material related then I don't want to waste your time.

@whittssg Sounds good. It seems that the error was actually coming from a different Material-based project that is not managed by the Angular Material team.

@apat183 I will be more than happy to continue investigating the source of the issues you are having if you would like. I do believe that it is not an issue with Angular Material. In keeping with our issue structure, since this is not our issue, I will be closing this issue. If you need, please create a new issue if another problem arises.

Thanks for everyone's hard work on this!

Ok thanks @bradrich. I've managed to isolate the issue (i think). It only occures when I call the mdpanel from a factory/service and not directly in a directive or component controller. I can use the same code in a directive or component controller and it works (after build) for some reason when I use the same code in a service (after build), it fails and gives error above. If I figure it out I'll post problem here for future if anyone has same issue.

Hi,

I just followed the issue for interest and didn't check all the provided code.

Though this (from one of your replies):

vendor.31fcb47b.js:formatted:7595Error: [$injector:unpr] Unknown provider: aProvider <- a

looks to me as if there's no $inject array for the service which uses mdPanel. Angular looks for "aProvider" which is because the variable is named "a" (by minification). You should check if the ng-annotate task worked correct there.

Maybe this is also the case for your latest tests using a service.

Thanks @oemmes

Yep I managed to get it sorted in the service by following the correct inject structure
e.g.

var controller = ['mdPanelRef', function (mdPanelRef) {
}]

I also do this for all my dialogs. ng-annotate doesn't show any errors but it's never worked for me on explicitly doing the $inject for my dialog controllers etc. I guess it's better practice to explicitly $inject myself then rely on ng-annotate.

Thank you @apat183. I was having the same issue with the $mdToast after minification. After following the correct inject structure, the problem was fixed.

I also met the same error. but I use gulp to minification my project code.

Here is my code.

        .module('ui')
        .service('NotificationDialogService', NotificationDialogService)

    /** @ngInject */
  function NotificationDialogService ($mdPanel, $document, SetReadService) {
...........
   }

the chrome console error:

vendor-5cdd3f6ca0.js:7 Error: [$injector:unpr] Unknown provider: eProvider <- e
http://errors.angularjs.org/1.4.14/$injector/unpr?p0=eProvider%20%3C-%20e
at vendor-5cdd3f6ca0.js:6
at vendor-5cdd3f6ca0.js:6
at Object.r [as get] (vendor-5cdd3f6ca0.js:6)
at vendor-5cdd3f6ca0.js:6
at r (vendor-5cdd3f6ca0.js:6)
at Object.i [as invoke] (vendor-5cdd3f6ca0.js:6)
at d.instance (vendor-5cdd3f6ca0.js:7)
at r._createController (vendor-5cdd3f6ca0.js:84)
at Object.i [as link] (vendor-5cdd3f6ca0.js:84)
at vendor-5cdd3f6ca0.js:91
(anonymous) @ vendor-5cdd3f6ca0.js:7

As my UI project, I used $mdDialog is fine. Only use $mdPanel has this error. Hope someone can fixed this problem.

@HelloJasonZhang please take a look at https://docs.angularjs.org/guide/di#dependency-annotation.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pablorsk picture pablorsk  Â·  3Comments

Dona278 picture Dona278  Â·  3Comments

ghost picture ghost  Â·  3Comments

buzybee83 picture buzybee83  Â·  3Comments

chriseyhorn picture chriseyhorn  Â·  3Comments