Why can't I pass an angular variable as a function parameter? - javascript

I'm trying to pass the follower through the followPerson() function. This works fine if I do followPerson(123). But when I do followPerson({{follower.follower}}) it doesn't fire.
{{follower.follower}} definitely works as it's shown in bold.
<div ng-repeat="follower in followers.followers">
<b>{{follower.follower}}</b>
<a ng-click="followPerson({{follower.follower}})">Follow</a>
</div>

You must not use interpolation ({{) for the arguments in the ng-click handler, it will just result in a parse error (If not using very old angular versions) due to invalid expression. You just need to pass the argument expression as is, angular will just evaluate is against the scope while evaluating the ng-click handler.
Just do:
ng-click="followPerson(follower.follower)"
Have a look at your console for errors.

Related

Passing object as a parameter in a template literal in javascript

I currently have an object which I want to pass as a parameter to another function inside a template literal:
var template = `<button onclick="onclick(${object})"></button>`;
However, this makes the parameter become a string value: [object Object] and doesn't pass the parameter. Is there any way to pass this parameter into the function?
Thank you very much in advance.
You are going to need to represent your object as a string. You can do this using JSON.stringify:
var template = `<button onclick="handleClick(${JSON.stringify(obj).split('"').join(""")})"></button>`;
You will need to escape double quotes (which this code does), and single quotes if used for your onclick event (this code doesn't).
onclick="onclick" actually calls window.onclick - meaning that it picks up clicks anywhere. You should use a different name (such as handleClick).
I would suggest refraining from using inline event listeners for reasons like this, and because they can cause issues if you ever need to adopt a content-security-policy.

Data-binding function parameter within ngFor

I'm trying to bind the value of cat to the (click) function parameter and understandably getting an error. Is there a way I can do this without looping a parent element of the <button>?
<button type="button" (click)="UpdateCategoryFilter({{cat}})" *ngFor="let cat of categories">
{{cat}}
</button>
Never combine [...] or (...) with {{...}} either one or the other, but not both at the same time
It should be
(click)="UpdateCategoryFilter(cat)"
{{...}} is also only for string interpolation. Values bound this way will always be strings, while [foo]="someValue" will pass someValue with the original type if foo is a property.
In html, the code you write in between the quotation marks of an event (such as (click)) is a pure typescript/js code, and as you would not write {{cat}} in your typescript code, you shouldn't write it in the place you wrote it.
Imagine that what you just tried to do is replacing the cat with it's code value, and then executing the code UpdateCatagoryFilter(x), where x is cat's value, and you try to use it as a variable name.
The meaning of (event)="..." syntax is: when an event event is emitted, execute the code ....

How to pass value of ng-repeat variable into input["file"]'s onchange function?

Inside of an ng-repeat="item in vm.items I have the following input["file"]:
<input type="file"
ng-attr-id="image{{item}}"
class="form-control"
accept="image/*"
onchange="angular.element(this).scope().vm.openFile(event, item)"
required>
I am calling vm.openFile using onchange instead of ng-change because ng-change is not supported for input["file"] types.
The problem, now, is that I am unable to pass item to my onchange function because of the following error:
Uncaught ReferenceError: item is not defined
How can I pass the value of item, which is just a string, into my onchange function within ng-repeat?
Since onchange is a build-in function, it is not compiled by angular but simply execute global-scope javascript. So, since there is no item variable in your global scope (which is fine), it crashes.
For the same reason as you could not simply write vm, but had to write angular.element(this).scope().vm, you will need to use the same for the item variable. Hence the html:
onchange="angular.element(this).scope().vm.openFile(event, angular.element(this).scope().item)"
Note that I don'tknow where this event variable comes from, so you may need to do the same for it if it is an angular thing.
Now this is a hack agisnt Angular design principles, so it would be better to use a directive as pointed out by David Williams comment.

error with name or value of a variable

I have a weird error with name of my variable :
when i try to call function map.removeLayer($scope.pimp.init.carte.layers[key].name);, it's doesnt works (no error, but action is not performed)
when i put manually map.removeLayer(markersLayer_2); it's good, markersLayer_2 is the value of $scope.pimp.init.carte.layers[key].name, and the action is performed
i don't why this difference, because with alert(); or console.log(); , $scope.pimp.init.carte.layers[key].name returns the good value (markersLayer_2).
Why i can't use $scope of angularjs in this leaflet function ?
Method removeLayer expects an instance of L.Layer, not the name property of that instance. Try: map.removeLayer($scope.pimp.init.carte.layers[key]); What you are doing now is using a string as the parameter. That won't work. You need to use the actual instance.
Reference: http://leafletjs.com/reference.html#map-removelayer

AngularJS : Difference between the $observe and $watch methods

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

Categories

Resources