How to know if $interpolate fails in AngularJS 1.2? - javascript

I'm trying to use the $interpolate service in AngularJS 1.2.16. However, I don't know how to check if Angular has properly interpolated all the vars in my string or not.
I noticed in AngularJS 1.3 they have added a new parameter AllOrNothing, which will cause the interpolate function to return an undefined if any embedded expressions fail to evaluate fully.
Any ideas how I can perform a similar check in 1.2? I would be okay looking for any embedded expressions, but Angular will strip them from the string if they are not specified in the context, so I can't even look for non-evaluated tokens in the returned string.

Use a unit test:
var exp = $interpolate('Hello {{name | uppercase}}!');
expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
References
AngularJS Source: interpolateSpec.js

Related

Can $parse or $eval be used to evaluate a stingified boolean equation?

I'm trying to understand $parse and $eval better and figure out if they are (or can be) used in a manner that I thought possible. I've created a plnkr to show my issue/question and reference their lines
I have an object with a boolean expression as a string value, which will be served to me from an external source (script.js line 6-10):
$scope.input123456abcdefg;
$scope.object123456abcdefg = {
disabled: "input123456abcdefg == 'hello'"
};
I have tried a few code walkthroughs, all of which have basically boiled down to (my understanding) of these 2 types of operations/functions (script.js line 12-15):
var template_v1 = $parse('object123456abcdefg.disabled');
$scope.expression_v1 = template_v1($scope);
$scope.expression_v2 = $scope.$eval('object123456abcdefg.disabled');
What I'm expecting (hoping) for either $parse or $eval to do is create an equivalent to (script.js line 17):
$scope.expression_v3 = $scope.input123456abcdefg == 'hello';
However, I'm only returned the same string as when I started, which you can see evaluated on the DOM (index.html lines 24 & 28).
Can $parse or $eval be used in this fashion, and if so where am I dropping the ball at? Or is there another option in Angular that is correct for performing this type of action?
As suggested by #dandavis I'd avoid eval() altogether if possible.Here a small explanation from MDN
Why do you require the value of object123456abcdefg.disabled to be passed in?
EDIT: If you really could not find another way of doing so, this is how you make your code work:
$scope.expression_v2 = $scope.$eval($scope.object123456abcdefg.disabled);

AngularJS : Why can't $interpolate render ng-style?

I have created a drop down input directive, where the user can pass in a template string to set what the list will actually render.
In my example I am passing in <div style="background-color: darkgrey" ng-style="{\'color\': isActive?\'red\':\'blue\'}">{{index}}</div> so it will render the items index number and then color it based on isActive. The index is show properly, and the background color is right but ng-style is being ignored.
I create the template in a setTimeout because I have to wait for ng-repeat to render the <li>.
setTimeout(function() {
var spanList = elm.find('li');
for (var index = 0; index < scope.list.length; index++) {
var listElm = angular.element(spanList[index]);
var listData = scope.list[index]
listElm.html($interpolate(scope.listTemplate)(listData));
}
}, 0);
I am iterating through the <li> elements and setting the template for each one. I am using $interpolate instead of $compile because using $compile would result in [[Object HTMLDivElement]] and I couldn't figure out why. From what I can tell $compile uses $interpolate anyways, and it works except that ng-style, ng-show, and ng-hide don't work. Why would angular's directives not work with $interpolate?
Here is the working example plunker.
$interpolate returns a function which returns a string. It is used to resolve {{bindings}}.
$compile returns a function which returns an html-element. It is used to compile raw (html) strings into html-elements and resolve angular-code inside of this string. $compile uses $interpolate to resolve any bindings inside this string.
In your case you probably want to use $compile and .replaceWith().
$interpolate is only for interpreting markup (example, "{{firstName}} {{lastName}}"):
AngularJS Documentation
$interpolate is a service used by $compile:
Compiles a string with markup into an interpolation function.
ngStyle, ngShow, etc do not rely on interpolation. Instead they rely on the $parse service to evaluate the AngularJS expression, and determine how to render the behavior.
$compile is appropriate in your scenario because it compiles the template HTML fragment by activating any directives within it, which indirectly calls $parse to evaluate expressions. Remember to append the template to the DOM before you $compile because directives may rely on parent directives higher up the DOM. I recommend the following pattern:
var e = angular.element(someTemplate);
element.append(e);
$compile(e)($scope);

Difference between angular.fromJson and $scope.$eval when applied to JSON string

In my angularjs apps, I usually parse a JSON string by using angular.fromJson, like so:
var myObject=angular.fromJSON(jsonString);
However, it seems that I would obtain the same result by using $scope.$eval:
var myObject=$scope.$eval(jsonString);
See this fiddle
Or by using vanilla javaScript, like so:
var myObject=JSON.parse(jsonString);
Is there any particular reason to use angular.fromJSON rather than JSON.parse?
Is there any possible issue when using $scope.$eval to parse a JSON string?
Check out the source code:
function fromJson(json) {
return isString(json)
? JSON.parse(json)
: json;
}
They're just passing through to JSON.parse.
As for $eval it shells out to $parse:
// $scope.$eval source:
$eval: function(expr, locals) {
return $parse(expr)(this, locals);
},
$parse source is too long to post, but it is essentially capable of converting inline (stringified) objects to real Objects and so it makes sense that in this case, it will actually convert your JSON as well.
(I did not know this until reading through the $parse source just now.)
Is there any particular reason to use angular.fromJSON rather than JSON.parse?
Nope, not really. Although they do check to you to ensure that you don't double-parse a JSON string, like so:
var jsonString = '{"foo":"bar"}';
var json = JSON.parse(jsonString); // Parsing once is good :)
JSON.parse(json); // Parsing twice is bad :(
Is there any possible issue when using $scope.$eval to parse a JSON string?
I don't think so off the top of my head, other than that you're doing more work than is necessary. So if you know you have JSON, there's no reason to use the heavier $parse function.
The above answer is almost correct. However, there is a potential issue with using $scope.$eval() to parse a JSON string, which does not exist with either JSON.parse() or angular.fromJson(): security. Angular allows an expression to contain complex JavaScript including function calls, conditionals with ?:, variable assignments, and so on. All of these are recognised and processed if you use $scope.$eval(), even if they were added by a malicious end-user.
JSON does not support any of those more complex JavaScript features, nor anything else potentially "dangerous". If you use a true JSON parser like JSON.parse() or angular.fromJson(), there is no chance of malicious code being injected and executed.
Since Angular expressions are isolated and evaluate only in the current $scope, the risk of code injection is somewhat mitigated - $scope.$eval() is far less dangerous than JavaScript's native eval() for parsing JSON. However there is still no reason to use either function for this purpose, since there is a potential security risk and using a proper JSON parser is likely to be faster.

Interpolating variables within already interpolated strings in angular

I have the following arrangement to fetch helptexts from a single Coffeescript file.
Coffeescript:
help.ex: '{{example.variable}} identifies enterprise data centers'
HAML:
%example-directive(attr='{{help.ex}}')
Now the example.variable is accessible but it is not getting interpolated on the view. This I guess is happening because the string as a whole is getting interpolated and compile is not running on the variables within. How do I get around this?
You can use the $interpolate service:
var exp = $interpolate(attrs.attr) // interpolate your attriubte
var interpolated = exp(scope) // evaluate it with the scope variable
Check this plunker

What is the significance of '?ngModel' when creating an AngularJS directive?

I'm working my way through the new ng-book. The chapter on filters includes a section on defining parsers with the following code:
angular.module('myApp')
.directive('oneToTen', function() {
return {
require: '?ngModel';
The first time I've seen the '?ngModel' syntax, and the Angular API docs don't provide much help. What does this syntax signify?
Thanks!
? is optional directive and ^ is parent directive
http://docs.angularjs.org/api/ng.$compile
(no prefix) - Locate the required controller on the current element. Throw an error if not found.
? - Attempt to locate the required controller or pass null to the link fn if not found.
^ - Locate the required controller by searching the element's parents. Throw an error if not found.
?^ - Attempt to locate the required controller by searching the element's parents or pass null to the link fn if not found.
The Required can be explained as:
[?][^][directiveName].
It is used to specify which directive controller should be used("inherited from"). So for instance a directive <column-item> needs to find the parent controller <crtl-grid>. There are a couple of symbols that can be used along with this attribute and they can also be combined:
^ = it indicates angular to seek up the DOM to find the directive.
? = it indicates angular that the directive is optional and angular will not throw an exception if not found.
So ?ngModel is saying that the ngModel needs be declared along with this directive.

Categories

Resources