Debugging Unknown provider in minified angular javascript - javascript

I'm having a hard time trying to pinpoint which, of the very many, methods I have in my angular app that would be causing the error:
Uncaught Error: [$injector:unpr] Unknown provider: nProvider <- n
This only happens once the javascript has been bundled & minified by ASP.Net.
I have ensured that all the controllers, and any other DI, is using the minification-safe method, I.E My controllers/service etc are using the method:
appControllers.controller('myCtrl', ['$scope', function($scope){
//......
}]);
I've gone through every JS file in our app - there are a lot... and can't find anything that violates this way of injecting dependencies - though there must be one somewhere...
Is there a better way to pinpoint which method could be causing this error?
Thanks

For anyone else struggling with this problem, I found an easier solution. If you pull open your developer console (on chrome) and add a breakpoint where angular throws the error:
Then, on the stack trace on the right, click on the first "invoke" you see. This will take you to the invoke function, where the first parameter is the function angular is trying to inject:
I then did a search through my code for a function that looked like that one (in this case grep "\.onload" -R public), and found 8 places to check.

For anybody reading this, using Angular 1.3
You can now use Angular's ng-strict-di check like this:
<div ng-app="some-angular-app" ng-strict-di>
...
</div>
This will give you an appropriate error message if you didn't load your dependencies using the array syntax.

I had the same problem and I found a solution that could be helpful for the rest. What I propose is basically what I saw in the comments and docs. If you are using Angular 1.3.0 or above, you can use this:
<html ng-app="myApp" ng-strict-di>
<body>
I can add: {{ 1 + 2 }}.
<script src="angular.js"></script>
</body>
</html>
In my case, I have everything within a file app.js so the only thing I need to do for finding my DI problems is to add this little code at the end:
angular.bootstrap(document, ['myApp'], {
strictDi: true
});
It's better documented in Angular Docs
I hope that helps. Good luck!

As mentioned in the comments, These are the steps I took to try and find my JS error.
If there is another, easier, solution, please feel free to post it and I may mark it as accepted.
Trying to debug minified code is a nightmare.
What I eventually did was copy my minified javascript, directly from the inspector in Chrome.
I then pasted the JS into http://www.jspretty.com/ - I had tried http://jsbeautifier.org/ but found their site froze with such large JS code.
Once it was 'pretty-fied' I created a test.js file in my solution and pasted the, now easier to read code, into it.
Quick step to comment out the #script tag in my _layout and add a link to the test.js file and I was ready to debug a now, far easier to read, chunk of Javascript.
It is still pretty awkward to traverse the call stack, though now you can see actual methods it makes it far less impossible.

Something that helped me solve this (finally!) was actually already in the angular docs! If you add the ng-strict-di attribute to your code wherever you define your ng-app, angular will throw a strict warning so you can more easily see what's going on in development mode. I wish that was the default!
See the argument list at the bottom of the ngApp docs.
https://docs.angularjs.org/api/ng/directive/ngApp

The way this works for me is the following:
1) have two test specification html files (unit test) minimized and plain
2) make sure the bundling of the files are in the same order as the plain spec file (JS script reference)
3) make sure to explicitly declare all dependencies (array or $inject declares see http://www.ozkary.com/2015/11/angularjs-minimized-file-unknown-provider.html)
When there is a mistake on the unit test (miminized reference) file, I can compare and make sure the reference of the files is in the correct order as the working file.
hope that help.

I had the similar issue and used lots of time to investigate and figured out it was the Chrome extension Batarang that was injecting the bad code and error in Angular looked exactly the same. It's really a pity it's so hard to find what exactly is causing the problem.

I had the similiar issue too. The solution is exacly the answer from ozkary point 3, that is to make sure to explicitly declare all dependencies including "resolve" part of your route.
Below is my code.
when('/contact/:id', {
controller: 'contactCtrl',
templateUrl: 'assets/partials/contact.html',
resolve: {
contact: ['ContactService', '$route', function(ContactService, $route) {
return ContactService.getContactDetail($route.current.params.id);
}]
}
})

For those who's bootstrapping their angularjs app.
angular.bootstrap(body, ['app'], { strictDi: true });
Don't forget to debug in non minified code and you should be able to figure out pretty quickly the malformed dependency injection.
The malformed injection is usually formatted like this :
...
.run([ function(ServiceInjected){
...
But should look more like this
...
.run(['ServiceInjected', function(ServiceInjected){
...
This is tested in angularjs 1.7.2

Related

OpenUI5 Error when loading DateTimeInput

While creating a simple MVC app with xmlviews in OpenUI5, i have run into an error.
I load OpenUI5 as it is mentioned in their getting started guide:
<script id='sap-ui-bootstrap' type='text/javascript'
src='https://openui5.hana.ondemand.com/resources/sap-ui-core.js'
data-sap-ui-theme='sap_bluecrystal'
data-sap-ui-libs='sap.m'>
</script>
Then load an xmlview:
var starterPage = sap.ui.xmlview("starterPage");
My problem is that when I include a DateTimeInput in my starterPage xmlview the loading fails with the following:
Error: found in negative cache: 'sap/m/DateTimeInput.js' from https://openui5.hana.ondemand.com/resources/sap/m/library-preload.json/sap/m/DateTimeInput.js: Error: failed to load 'sap/ui/thirdparty/mobiscroll/js/mobiscroll-core.js' from ./sap/ui/thirdparty/mobiscroll/js/mobiscroll-core.js: 0 - NS_ERROR_DOM_BAD_URI: Access to restricted URI denied
Does anybody have an idea?
Thanks!
I think there is either something wrong with your view definition, or possibly your network permissions. I created a simple jsbin example (http://jsbin.com/kukoju/1/edit?html,console,output) that I think does essentially what you described and it seems to work fine for me. In attempting to simplify the problem I omitted the use of the XML view and simply directly instantiated the DateTimeInput in javascript. If my jsbin example works for you then I'd recommend you post more of your code so we can see what might need to be changed. If that doesn't work then I suspect you need a local system administrator to help you with the problem.
If you run a simple Openui5 probably it has just a controller. The mentioned error happens when you tried to use a third party library and it's not implemented correctly. just check out the controller files be sure that there is no third party library included.
Or
The DateTimeInput what you used has a dependency and the dependency files are not found.
May could be better to use this control
https://openui5.hana.ondemand.com/#/api/sap.m.DateTimeField

Angular gives blank page when i use ui.bootstrap in my controller

I am trying to use the the angular bootstrap when i try to add the dependency in my controller and start the server with grunt serve i get a blank page.Please have a look at the bower components in the screen shot.
When i try to use it in angular.module('kbv1App', ['ui.bootstrap']).controller it fails if i remove the [ui.bootstrap] it works fine.
Any idea wha will be the issue?
Update. Console error
[$injector:modulerr] Failed to instantiate module ui.bootstrap due to: [$injector:nomod] Module 'ui.bootstrap' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument. http://errors.angularjs.org/1.2.18/$injector/nomod?p0=ui.bootstrap minErr/<#http://localhost:9000/bower_components/angular/angular.js:78:5 setupModuleLoader/</module/<#http://localhost:9000/bower_components/angular/angular.js:1645:1 ensure#http://localhost:9000/bower_components/angular/angular.js:1567:5 module#http://localhost:9000/bower_components/angular/angular.js:1641:7 createInjector/loadModules/<#http://localhost:9000/bower_components/angular/angular.js:3817:11 forEach#http://localhost:9000/bower_components/angular/angular.js:320:7 loadModules#http://localhost:9000/bower_components/angular/angular.js:3811:5 createInjector/loadModules/<#http://localhost:9000/bower_components/angular/angular.js:3818:11 forEach#http://localhost:9000/bower_components/angular/angular.js:320:7 loadModules#http://localhost:9000/bower_components/angular/angular.js:3811:5 createInjector#http://localhost:9000/bower_components/angular/angular.js:3751:3 bootstrap/doBootstrap#http://localhost:9000/bower_components/angular/angular.js:1410:1 bootstrap#http://localhost:9000/bower_components/angular/angular.js:1425:5 angularInit#http://localhost:9000/bower_components/angular/angular.js:1338:5 #http://localhost:9000/bower_components/angular/angular.js:21713:5 jQuery.Callbacks/fire#http://localhost:9000/bower_components/jquery/dist/jquery.js:3119:1 jQuery.Callbacks/self.fireWith#http://localhost:9000/bower_components/jquery/dist/jquery.js:3231:7 .ready#http://localhost:9000/bower_components/jquery/dist/jquery.js:3443:3 completed#http://localhost:9000/bower_components/jquery/dist/jquery.js:3474:3
The reason people are using angular-ui-bootstrap is to avoid using jquery and bootstrap.js (which relies on jquery) and opt for an Angular solution. So my first attempt at getting this app working is to
Remove jquery.js, jquery-ui.js, and bootstrap.js out of the page.
Start from just plain Angular + Angular UI Bootstrap first. Try some examples from http://angular-ui.github.io/bootstrap/ if you want to get familiar with the directive usage.
Then, if you really need to, just add jquery back in later. But from my experience, you won't really need to if you stick to Angular way of coding. If you come from a strong jquery background and just start coding on Angular, I recommend you read this: https://stackoverflow.com/a/15012542/3788115
The component `angular-bootstrap` should have two javascript files:
bower_components/angular-bootstrap/ui-bootstrap.js
bower_components/angular-bootstrap/ui-bootstrap-tpls.js
You only include the templates.
Edit: Corrected in the comments.
Use Chrome Canary for easier debugging, you will see the full error message instead of Uncaught object.
add ['ui.bootstrap'] on the main app.js

BreezeJS RequireJS support unstable (knockout example)

As I'm trying to compile my project with breeze and requirejs for production, I'm running into multiple issues. Unrolling this, I tried starting fresh with the Knockout RequireJS example.
After I installed MVS2013Pro I was able to run the project, but not without issues:
window.breeze is defined so it has been leaked to global scope (this
should not happen with RequireJS)
Hitting F5 Refresh will crash with
Uncaught Error: Can't find breeze and/or Q (breeze savequeuing)
Uncaught TypeError: undefined is not a function (breeze dataservice)
With these errors I'm not even trying to establish my grunt requirejs (r optimizer) task. As these are the root of my problems.
Note: I'm not searching for a knockout solution, my stack actually is: MongoDataService+Breeze+SaveQueueing+RequireJS+AngularJS+Socket.IO+Cordova
window.breeze
You're right that breeze sneaks back into the browser way down at the bottom of breeze.debug.js:
if (global.window) {
global.window.breeze = breeze;
}
We don't know why we put that in the code base. No one remembers. Coming at the end as it does, it clearly isn't needed by Breeze itself.
I commented it out in preliminary testing and that seems to do the trick. The window.breeze becomes undefined in the Todo-KO-Require sample; it remains defined (properly) in samples that do not use require.js.
We don't think this would be a breaking change for anyone ... and the remedy is simple enough: define it yourself at the top of your app.
We'll probably remove these lines for the next release unless we discover a reason to do otherwise.
F5 fail?
I can't repro this at all. I suspect your are conflating your discovery that breeze is inadvertently in the global namespace with your efforts to write an Angular app that uses breeze.savequeuing.js.
Why do I think this? Because the error you describe arises when trying to use breeze.savequeuing.js in an Angular app which is explicitly disallowed in the comments (line #14) of v.1.0.4:
Depends on Breeze (which it patches) and Q.js (not for use in Angular ... yet)
You no doubt omitted Q.js from your required libraries and it all goes to custard from there.
I'm personally allergic to the "save-when-user-changes-anything" user experience that made save queuing necessary. I'm almost sorry I wrote it. But there it is.
The apparently dependence on Q.js is the reason it isn't available for Angular apps as written. It's actually pretty easy to make it Angular-ready now because we recently (quietly) made accessible the component that Breeze is using for promises
breeze.Q // returns the promises component currently used by Breeze
Therefore, you could change the one reference to Q on line #104 to
var deferredSave = breeze.Q.defer();
This should work when using breeze v.1.4.14 and later. I haven't fully tested it yet.
This change (or something like it) likely will find its way into breeze.savequeuing.js v.1.1.0 (as I just pushed a non-release version of that).

angular ngRoute breaks when using base tag

Can anyone tell me what is wrong with my code? I put up a simple webpage to show you: http://plnkr.co/edit/TkADpfgchYVdvNTqRPFT?p=preview
I'm using base tag with a sub dir along with html5mode and the beta version
I don't think you're really doing anything wrong. I think its a bug in the new release candidate. You're not really even doing anything special. Its just in your $locationProvider.html5Mode(true); call. That function calls angular's beginsWith function, which calls .indexOf on the url string, which is apparently undefined. I would suggest creating a bug for it on angular's github page. You can do that here. I would simply post this issue and the link to your plunker and they should be able to handle it.
That's precisely why they ask us to test the rc's. Good find. I'm not actually using HTML5Mode, so I hadn't found this particular bug yet.
You are trying to call a method of an undefined variable. You should probably add a check such as:
if (typeof variable ==="undefined")

Minified JS only works by pasting source into Controller

I'm not sure if there is a clear way for me to show / describe the problem that I'm having. But here goes:
I've developed an app with AngularJS (have not put live yet). It was decided that we needed tooltips for some of the metrics on the tables. We liked the general look of TipTip jQuery Plugin.
On my index file I correctly include the minified.js:
<script src="../assets/javascripts/app/jquery.tipTip.minified.js"></script>
(yes, the path is correct. I can click on the link in chrome developer tools and see the source file).
In my controller, I call it with this:
$scope.addTolltips = function() {
$timeout(function(){$('.results-metrics').tipTip({maxWidth:"300px", defaultPosition: "top"});},500);
}
I added the $timeout to make sure there was enough time for dynamic stuff on the page to be load in the DOM. I know it's probably not necessary anymore though.
But when tipTip() is being called I get a console error:
TypeError: Object [object Object] has no method 'tipTip'
However, if I take the minified source and paste it into my controller before the tipTip(), then everything works perfect. Any thoughts?
angularjs provides jQuery functionality via the angular.element function (http://docs.angularjs.org/api/angular.element), so you should use it instead of $ (however, I cannot explain why $ isn't working in your case)

Categories

Resources