in some cases, the angular engine doesn't output the raw javascript error. For example
myapp.directive('helloWorld', function() {
return {
scope: '#',
restrict: 'AE',
template: '<p ng-click="clearMessage2()">Hello, World! {{message}}</p>',
link: function(scope, elem, attrs) {
scope.clearMessage = function() {
scope.message = '';
}
}
}});
When I click on p element produced with directive I'm expecting the error in console to say clearMessage2() is not defined, but this doesn't happen and the only way to check things is to use console.log inside clearMessage definition.
Is it possible to change that behavior of angular.js and do not hide errors happening inside JS code?
It is possible, but not recommended. The problem is that angular does not execute the method in the ng-click directive as is (like in regular onclick), but instead evaluates expressions using the $parse service. From the angular doc:
Angular does not use JavaScript's eval() to evaluate expressions.
Instead Angular's $parse service processes these expressions.
The implementation of expression evaluation in Angular is deliberately forgiving.
In JavaScript, trying to evaluate undefined properties generates ReferenceError or TypeError. In Angular, expression evaluation is forgiving to undefined and null. It makes more sense to show nothing than to throw an exception if a is undefined (perhaps we are waiting for the server response, and it will become defined soon). If expression evaluation wasn't forgiving we'd have to write bindings that clutter the code
So the $parseProvider will not execute an undefined function at all, instead it will execute a noop function (which is an implementation of a null object pattern). Here is an excerpt from the $parseFunctionCall method:
var fn = fnGetter(scope, locals, context) || noop;
The execution of a null object will do nothing, and that is what's happening. You could probably achieve what you want by modifying the $parseFunctionCall to execute any function, instead of executing a noop function.
Changing code looks like the only option since configuration of these services is not sufficient for your use-case. However, i don't think it's a recommended approach unless you know the Angular API very well.
For additional reading:
Angular expressions
$parse service
Related
I use self invoking functions to include all the javascript code inside an angular controller (I think I saw it somewhere as a best practice). So my controller looks like this:
(function() {
// code
})()
I use gulp to merge all the controllers into one file. My question is this.
Does this mean that all of my Javascript code will be invoked and executed when my application starts?
If so, I guess that this is not a very good approach.
Are there any solutions to that issue? Any comments?
Thanks
No, not all the code gets executed. When you define your Angular modules
(function() {
'use strict';
angular
.module('myModule', [])
.controller('myController', ['$http', myControllerFunc]);
function myControllerFunc ($http) {
// ...
}
})();
what gets executed are only the angular methods to register the module and the controller. But the actual controller logic is in the callback function, and that gets only called when the controller is invoked (e.g. by the router).
So, its all good, and wrapping the code in anonymous functions is a good idea to keep, for example myControllerFunc, out of the global namespace.
It does not matter wether you define your code into an anonymous function.
Javascript client ( browser for this matter ) will have to parse your code either way.
So if you have something callbable in the anonymous function, it will get executed. If you have a declared var with decoupled methods, it will just define that var, just like it would do in a simple separated script inclusion.
Javascript is "parsing" your javascript either way, but will never call methods that are not called by your code. Of course it needs to know that when you call foo( bar ) that foo exists, so it will parse it. It's common javascript.
What does the following function wrapped by scope.$apply do? I can't seem to find the answer to this, but I see examples where it is used in directives.
scope.$apply(function() {
fn(scope, {
$event: evt
})
});
The closest explanation I could find implies that this might be used when the event that you want to respond to is not handled by Angular directives. Here is the explanation I am referring to.
If someone could provide the intended use of this pattern and what it means, it would be appreciated.
EDIT 1
I should have seen this earlier. Must need more sleep.
Since my example is not a complete working one. It makes a lot more sense after looking at the referenced explanation carefully.
The fn(scope, {$event: evt}) call is invoking the parsed reference to a custom function via the directive parsed in the following line:
var fn = $parse(tAttrs.myContextmenu);
So the target function implementation is capturing a specific event via the directive and then suppressing it.
So I guess this is useful when you do not want to clutter directives with controller specific functions and maybe fire a different event in response to another event then let a controller handle it.
scope.$apply is used to manually trigger Angular's digest cycle for any async events that happen outside of Angular's execution context.
One such async event is element.on("click", function(e){...}) (or any other event related captured with .on), but could also be other async function outside of Angular context.
The second part is an invocation of the "$parsed" expression. It accepts a scope as a parameter and a map of "local" variables, such as {$event: evt}. The intent is every similar to what scope: "&" is doing - but without creating an isolate scope. For example, if the expression is:
<my-directive p="doSomething(foo)">
then, if doSomething(foo) is $parsed, the caller can supply the value of foo:
var parsedFn = $parse(attrs.p);
parsedFn(scope, {foo: 5})'
This will cause the invocation of doSomething(5)
Posting an answer to this since it makes sense to me (see my edit).
The fn(scope, {$event: evt}) call is invoking the parsed reference to a custom function via the directive parsed in the following line:
var fn = $parse(tAttrs.myContextmenu);
So the target function implementation is capturing a specific event via the directive and then suppressing it.
So I guess this is useful when you do not want to clutter directives with controller specific functions and maybe fire a different event in response to another event then let a controller handle it.
Here we can see which types of objects in JavaScript/ECMAScript evaluate to false.
My question is: if a variable evaluates to true, is it guaranteed to have a hasOwnProperty method?
In other words, is the following test safe?
if (bar && bar.hasOwnProperty("foo")) { ... }
My goal is to prevent exceptions like Cannot read property 'hasOwnProperty' of null.
My application scenario: in an AngularJS $http service error handler I want to be prepared for all situations. This is a little difficult for me, because I am not tremendously experienced with JavaScript and the different situations in which this error handler might be called can not easily be tested for. The error handler function has the following signature:
function(data, status, headers, config) {}
In the function body I evaluate data like so:
if (data && data.hasOwnProperty("error")) {
alert(data.error);
}
Does this look safe to you under all circumstances? Safe in the sense that this test does not throw an exception, no matter how AngularJS actually calls the error handler.
No.
Here's one:
var bar = Object.create(null);
Here's another one with hasOwnProperty, but not much better:
var bar = {hasOwnProperty:function(){ throw "bouh" }};
But you can call
Object.prototype.hasOwnProperty.call(bar, "foo")
Note that you may avoid the evaluation to truthy by doing
if (Object.prototype.hasOwnProperty.call(Object(bar), "foo")) {
I'm using AngularJS and I've created a custom exception handler.
angular.module('moduleName')
.factory('$exceptionHandler, () => {
return (exception, cause) => {
try {
var someService = $injector.get('serviceName');
someService.alert(exception);
}
catch (ex) {
window.alert(ex);
}
};
})
I caught up a situation when i forgot to run a script (in the html page) of one of the injections services that the service (named 'serviceName') are using. This has caused an exception when there is a use of the 'alert' function of the service.
I added the try/catch code in order to use regular 'alert' function whenever the service is malfunction (wrong injection or couldn't initialized) so the flow of the application won't hurt and in case of an exception handler exception catch, the code will run with or without the service.
However, even with the try zone, when there is use of the alert function of the service (when the service is malfunction), the $exceptionHandler function is invoked again instead of reaching to the catch zone...
Is there a way to get to the catch zone instead of invoking again the $exceptionHandler function? or is there a different way i could use in order to see if the service is good to use and all of his injections were loaded correctly?
Thanks in advanced
Update:
Perhaps the way the function is called is to blame, so here's to it:
2 JS files Main.js: self invoking (non-strict) function that adds an event listener for the '(on)load' event. The callback calls a loader function, that parses the location.pathname, and calls an init function, and detaches/removes the '(on)load' listener & returns null (explicitly).
PageSpecific.js: contains the _init function, adds a couple of event listeners to the body.
One of these listeners' callback (also returned from a closure) calls the strict function that uses argument.callee as a reference for recursion. The closure that returns the event handler may -depending on the browser- or may not bind and unbind other events, but I think that's irrelevant here, as this is to imitate an onchange event in IE <9
I hope this is reasonably clear, so its: anon. F => eventlistener => handler (named but declared in anon F) => pageloader => init => eventListener binding function returned by closure => calls strict function
Incidentally: Here's a trimmed down version of the _init function that is called, that I'm actually using. More specifically: the closure that binds the event Listener and - handler together. Its another one of my length questions, to which nobody seems to know the answer... hint ;-)
I'm debugging some fairly large (and complex) JavaScripts. In doing this, I noticed that I have a function, using strict mode that works fine but should, if I'm not mistaken, throw errors. Since the scripts are fairly sizeable and complex (event delegation, stacked closures etc), here's a simple example:
function withCalleeRecursion(foo)
{
'use strict';//strict throws typeError on arguments.callee
foo = foo.replace(/(a|b)+/gi, function (p1,p2)
{
if (p1.match(/(a|b){2,}/i))
{
return p1.replace(/(a|b)/gi,arguments.callee);//no errors
}
return (p2.match(/a/i) ? 'X':'Y');
});
return foo;
}
(function()
{//not strict
alert(withCalleeRecursion('Abba makes me barf'));
})();
In my actual script, this works perfectly fine. When I pasted this both in Firebug and chrome console, an error is thrown, though. I've tried this code here, so IE should throw errors, too, but when I run the code in IE's debugger, it works just fine. As far as I can work out, changing the doctype (tried html5 and html4) makes no difference.
Am I right in thinking that (most) browsers aren't as strict with the 'use strict'; directive as it's name suggests? It would seem that the browsers choose to ignore it when a possible error is detected when parsing the script. Is this true?
Meanwhile, I have made a slight change to the function, just out of precaution. Since I've seen quite a few questions here of people wondering how to get the callee reference in strict mode, I'm pasting it here, too:
function withCalleeRecursion(foo)
{
'use strict';
foo = foo.replace(/(a|b)+/gi, function abR(p1,p2)
{
if (p1.match(/(a|b){2,}/i))
{
return p1.replace(/(a|b)/gi,abR);
}
return (p2.match(/a/i) ? 'X':'Y');
});
return foo;
}
Name the callback, that's all.
It's probably because browser consoles use eval(), which changes things. Although putting "use strict"; at the start of a string of code that is passed to eval() works as expected, it's possible that console implementations prepend code to the string you've typed into the console, meaning that "use strict"; is no longer the first statement executed and is therefore ignored.
There's a reference to this and a suggested workaround in the following article:
http://javascriptweblog.wordpress.com/2011/05/03/javascript-strict-mode/
The suggested workaround is to wrap code in the console within a function that is immediately executed:
(function() {
"use strict";
nonExistentVariable = 1; // Error is now thrown
})();
Maybe this article can help you to understand more. Anyway the solution is the one you mention, the error is because access to arguments.caller and arguments.callee throw an exception in strict mode. Thus any anonymous functions that you want to reference will need to be named.