I have an ng-click with 2 functions in it.
Function1: A function in a directive that sets a scope variable to
true/false
Function2: A function in the controller
Right now in Function2 in the beginning I check the value of the scope variable from Function1 and if it's false I return false(i.e. stop it).
So my question is: can the Function2 not be called in case the first one returns false without writing anything in the Function2?
Thank you.
Try this:
ng-click="directiveFunction(); booleanVariable ? controllerFunction() : noop();"
From here: https://docs.angularjs.org/guide/expression
No Control Flow Statements
Apart from the ternary operator (a ? b : c), you cannot write a control flow statement in an
expression. The reason behind this is core to the Angular philosophy that application logic
should be in controllers, not the views. If you need a real conditional, loop, or to throw
from a view expression, delegate to a JavaScript method instead.
Related
This question already has answers here:
How to parseInt in Angular.js
(7 answers)
Closed 6 years ago.
I am scratching my head here. I am using angularJS and trying to use the expression that contains call to parseInt.
{{0 == 2}}
...prints out false as expected.)
However, when I am trying:
{{parseInt(0) == parseInt(2)}}
... it prints out... true !
How can this be possible?
Angular does not use JavaScript's eval() to evaluate expressions.
Instead Angular's $parse service processes these expressions.
Angular expressions do not have access to global variables like
window, document or location. This restriction is intentional. It
prevents accidental access to the global state – a common source of
subtle bugs.
Refer
In your html
Both parseInt(0) and parseInt(2) are undefined in your html.
So {{undefined==undefined}} is true.Beacause parseInt is a Javascript function.So you cant access the parseInt function in side {{}}. [Here parseInt is not a scope variable]
Solution
If you wish to do this,
define parseInt in your controller,
$scope.parseInt = parseInt;
Then you can use the parseInt method in your html
That's because parseInt is not defined in your scope.
http://jsfiddle.net/halirgb/Lvc0u55v/
You can't execute regular JS in an angular expression. Your expressions will be evaluated against the current scope. So, parseInt is undefined in the current scope.
If you set parseInt as a function reference, it will work.
$scope.parseInt = parseInt;
This is because the view is attached to the controller via scope.
So whatever we write in view either a variable or a function or anything it's rendered by appending $scope in front of it.
eg.
a is rendered as $scope.a in the view
So when we write parseInt, its rendered by $scope.parseInt which is not defined.
FIX- define $scope.parseInt = parseInt in the controller attached to the particular view
You have comparing both undefined values so result will be true.
You cannot call a javascript method(parseInt) via angular directives(ng-blur,ng-change,..) either you can achieve by making angular functions.
Solution 1:
{{0*1 == 2*1}}
Just do a trick to convert to Integer by multiply with 1 (0*1 = 0, 2*1 =1).
Solution 2:
{{parseInt(0) == parseInt(2)}}
Controller:
// To Convert specific format
$scope.parseInt = funtion(value){
return parseInt(value,10);
}
or
$scope.parseInt = parseInt;
reference here
I need to initialize an object in my view and assign a reference to it.
Can I achieve this by using ng-init? Is it an assignment by value or reference?
<ANY ng-init="objA = objB"> ... </ANY>
Any help will be appreciated!
Move assignment to controller init() method.
ng-init is directive that have a very lot of side effects and hardly to trace it down. For example: when you use ng-init in directive template for creating/editing item and you assign some model value in it - you will achieve problem with editing that actually should use already existing value.
As well side effect of it is executing few times when you add ng-if.
Usage ng-init in templates are your own risk.
Right way: controller data should be defined at start of module - in any case any view started in order: $state -> resolve() -> controller -> template -> directive. It's not a good idea to fool yourself with not existing data until it will be created by magic.
In case of repeaters when you have for example empty {} and you need to display it like possibility to fill yet empty input, as I mentioned - you need to run function on init that can define empty or extend existing model by passing actual model.
I use a same controller twice on my page, with same data, but i display it not in the same way (not same parts of the array).
I can see with ng-inspector that the scope is correctly updated when i perform some change, and it's duplicate. But in the view, it's doesn't change ! A simple param to false by default and passed at true with a simple timeout, in the view, it's always to false.
If i display only one time the ng-controller, the view it's updated.
How to correct that ?
Ok, so you didn't actually give much in the way of code, but this sounds like you're falling victim to one of the classic scope blunders. The first thing to try is to use properties of objects, not primitives on the scope.
This means instead of using this code ---
$scope.myBool = false;
{{myBool}}
use this code ---
$scope.myBool = { value: false };
{{myBool.value}}
The reason being is that Angular likes to do funny stuff like use prototype for new scopes. This means you'll get the prototype of the parent scope, and then when you instantiate your scope, you can override the parents prototype with your new value, without changing the parents value. You get past this by using an object on the scope instead.
The second option that might be occurring is you're doing something that isn't causing an angular digest cycle to happen. You might need to manually kick one off.
Without seeing any code, there's no telling, though.
I know that both Watchers and Observers are computed as soon as something in $scope changes in AngularJS. But couldn't understand what exactly is the difference between the two.
My initial understanding is that Observers are computed for angular expressions which are conditions on the HTML side where as Watchers executed when $scope.$watch() function is executed. Am I thinking properly?
$observe() is a method on the Attributes object, and as such, it can only be used to observe/watch the value change of a DOM attribute. It is only used/called inside directives. Use $observe when you need to observe/watch a DOM attribute that contains interpolation (i.e., {{}}'s).
E.g., attr1="Name: {{name}}", then in a directive: attrs.$observe('attr1', ...).
(If you try scope.$watch(attrs.attr1, ...) it won't work because of the {{}}s -- you'll get undefined.) Use $watch for everything else.
$watch() is more complicated. It can observe/watch an "expression", where the expression can be either a function or a string. If the expression is a string, it is $parse'd (i.e., evaluated as an Angular expression) into a function. (It is this function that is called every digest cycle.) The string expression can not contain {{}}'s. $watch is a method on the Scope object, so it can be used/called wherever you have access to a scope object, hence in
a controller -- any controller -- one created via ng-view, ng-controller, or a directive controller
a linking function in a directive, since this has access to a scope as well
Because strings are evaluated as Angular expressions, $watch is often used when you want to observe/watch a model/scope property. E.g., attr1="myModel.some_prop", then in a controller or link function: scope.$watch('myModel.some_prop', ...) or scope.$watch(attrs.attr1, ...) (or scope.$watch(attrs['attr1'], ...)).
(If you try attrs.$observe('attr1') you'll get the string myModel.some_prop, which is probably not what you want.)
As discussed in comments on #PrimosK's answer, all $observes and $watches are checked every digest cycle.
Directives with isolate scopes are more complicated. If the '#' syntax is used, you can $observe or $watch a DOM attribute that contains interpolation (i.e., {{}}'s). (The reason it works with $watch is because the '#' syntax does the interpolation for us, hence $watch sees a string without {{}}'s.) To make it easier to remember which to use when, I suggest using $observe for this case also.
To help test all of this, I wrote a Plunker that defines two directives. One (d1) does not create a new scope, the other (d2) creates an isolate scope. Each directive has the same six attributes. Each attribute is both $observe'd and $watch'ed.
<div d1 attr1="{{prop1}}-test" attr2="prop2" attr3="33" attr4="'a_string'"
attr5="a_string" attr6="{{1+aNumber}}"></div>
Look at the console log to see the differences between $observe and $watch in the linking function. Then click the link and see which $observes and $watches are triggered by the property changes made by the click handler.
Notice that when the link function runs, any attributes that contain {{}}'s are not evaluated yet (so if you try to examine the attributes, you'll get undefined). The only way to see the interpolated values is to use $observe (or $watch if using an isolate scope with '#'). Therefore, getting the values of these attributes is an asynchronous operation. (And this is why we need the $observe and $watch functions.)
Sometimes you don't need $observe or $watch. E.g., if your attribute contains a number or a boolean (not a string), just evaluate it once: attr1="22", then in, say, your linking function: var count = scope.$eval(attrs.attr1). If it is just a constant string – attr1="my string" – then just use attrs.attr1 in your directive (no need for $eval()).
See also Vojta's google group post about $watch expressions.
If I understand your question right you are asking what is difference if you register listener callback with $watch or if you do it with $observe.
Callback registerd with $watch is fired when $digest is executed.
Callback registered with $observe are called when value changes of attributes that contain interpolation (e.g. attr="{{notJetInterpolated}}").
Inside directive you can use both of them on very similar way:
attrs.$observe('attrYouWatch', function() {
// body
});
or
scope.$watch(attrs['attrYouWatch'], function() {
// body
});
I think this is pretty obvious :
$observe is used in linking function of directives.
$watch is used on scope to watch any changing in its values.
Keep in mind : both the function has two arguments,
$observe/$watch(value : string, callback : function);
value : is always a string reference to the watched element (the name of a scope's variable or the name of the directive's attribute to be watched)
callback : the function to be executed of the form function (oldValue, newValue)
I have made a plunker, so you can actually get a grasp on both their utilization. I have used the Chameleon analogy as to make it easier to picture.
Why is $observe different than $watch?
The watchExpression is evaluated and compared to the previous value each digest() cycle, if there's a change in the watchExpression value, the watch function is called.
$observe is specific to watching for interpolated values. If a directive's attribute value is interpolated, eg dir-attr="{{ scopeVar }}", the observe function will only be called when the interpolated value is set (and therefore when $digest has already determined updates need to be made). Basically there's already a watcher for the interpolation, and the $observe function piggybacks off that.
See $observe & $set in compile.js
I am trying to understand what angularjs $parse service does. I have read the official documentation at https://docs.angularjs.org/api/ng/service/$parse but that's not really helping. Searching online did not render any good examples.
Any help will be appreciated.
I was going to explain but could not do a better job than this post
"$parse takes an expression, and returns you a function. When you call the returned function with context as first argument. It will execute the expression with the given context."
In the simplest form: It's main purpose is for example to access some tags click function with the right context inside a directive without tight coupling so you can execute it (maybe with some extra params).
The purpose of $parse from my POV is to let us evaluate a "property" from a given $scope. The result of calling $parse is "property", for example:
my controller
$scope.author.name = "Hello World";
somewhere else under the same controller:
var property = $parse("author.name");
Property Getter: property($scope); in this case it is evaluated against the same scope.
Property Setter: property.assign($scope,'Felipe'); assigns a new value to the author name.
$scope give us the context where to evaluate or search for the "property".
I have found them useful when creating directives to still maintain the directive decoupled from the controller but still needing to interact with objects present in the controller.
$parse takes in a string and returns you a function. Below is a simple example of it in action
http://plnkr.co/edit/nicdbwVL2ZZbljZy2Z9S