I have tried to pass AngularJS variable as argument value inside onclick() to call javascript function. Can anyone guide me on how to do it?
My code:
<div onclick="deleteArrival({{filterList.id}})" class="table-icon deleteIcon">{{filterList.id}}</div>
You should be using ng-click, there is no reason to use onclick as angular provides you with this functionality
<div ng-click="deleteArrival(filterList.id)"
class="table-icon deleteIcon">{{filterList.id}}</div>
You should then move your function into your AngularJS Controller, and bind it to the scope
$scope.deleteArrival = function(filterListId) { ... };
If you ABSOLUTELY need to use onclick to call an external function, you could change the function to something like this in your scope, still using the ng-click attribute above:
$scope.deleteArrival = function(filterListId) { window.deleteArrival(filterListId); };
However I can't see a reason not to move it into your scope
If you still want to use onclick , this is work for me , I hope it work for you too.
<div id="{{filterList.id}}" onclick="deleteArrival(this.id)" class="table-icon deleteIcon">{{filterList.id}}</div>
Im not going to second guess your reasons for not using ng-click, as other contributors have pointed out you really 'ought'. However if you really want/need to, heres my suggestion by using 'this' and data attributes.
<div data-filterListId="{{filterList.id}}" onclick="deleteArrival(this)" class="table-icon deleteIcon">{{filterList.id}}</div>
function deleteArrival(arrivalElem) {
alert('myId=' + arrivalElem.getAttribute("data-filterListId"));
}
You could easily solve your problem using ng-click but you should have deleteArrival method in your scope.
Markup
<div ng-click="deleteArrival(filterList.id)" class="table-icon deleteIcon">
{{filterList.id}}
</div>
Above thing is easily possible using ng-click directive and having that function inside controller scope, only the thing is you need to assign your java-script function reference to controller scope variable. No need to rewriting the function in your scope again. Pass the reference of function will do the trick.
Markup
<div ng-click="deleteArrival(filterList.id)" class="table-icon deleteIcon">
{{filterList.id}}
</div>
Controller
//assign javascript method reference in controller
$scope.deleteArrival = deleteArrival;
You are not allowed to create a binding for event handler attributes like onclick, onload, onsubmit, etc. in angularjs because,
there is no practical value in binding to these attributes and doing so it only exposes your application to security vulnerabilities like XSS. For these reasons binding to event handler attributes (all attributes that start with on and formaction attribute) is not supported in angularjs.
For your case,
Inside ng-repeat, use ng-click for sending values to your function and declare that function in controller.
See here for documentation of ng-click
Hope this helps !
try this without the curly braces
deleteArrival(filterList.id)
I had a case where I could not use ng-click due to window binding. Did not get direct answer but the below did work for me. I know it is not a good solution but workable in my case.
angular.element(this).scope().ctrlName.variable
You can try using your own class structure. So the click will be as below:
onclick="test(angular.element(this).scope().ctrlName.ObjName.variable)"
$scope.getpop = function(id){
alert(id);
}
<span ng-click='getpop({{x.Code}})' class="btn-default btn">{{ x.title }}</span>
<b>This works perfect for me !</b>
My use case was where my application is relying on a large JavaScript file of functions that are not written in Angular. For this, I added a function in my controller that connects to one of these JS functions:
$scope.controllerFunction = function() {
javaScriptFunction('foo');
}
javascriptFunction(parameter){
let variable = parameter
}
Then in my view, making use of ng-click, I accessed the controller function with:
ng-click="controllerFunction()"
For me, the "onclick="deleteArrival(this.id)" example returns undefined. The above was the best solution.
Related
Here is my plnkr: http://plnkr.co/edit/n8cRXwIpHJw3jUpL8PX5?p=preview You have to click on a li element and the form will appear. Enter a random string and hit 'add notice'. Instead of the textarea text you will get undefined.
Markup:
<ul>
<li ng-repeat="ticket in tickets" ng-click="select(ticket)">
{{ ticket.text }}
</li>
</ul>
<div ui-if="selectedTicket != null">
<form ng-submit="createNotice(selectedTicket)">
<textarea ng-model="noticeText"></textarea>
<button type="submit">add notice</button>
</form>
</div>
JS part:
$scope.createNotice = function(ticket){
alert($scope.noticeText);
}
returns 'undefined'. I noticed that this does not work when using ui-if of angular-ui. Any ideas why this does not work? How to fix it?
Your problem lies in the ui-if part. Angular-ui creates a new scope for anything within that directive so in order to access the parent scope, you must do something like this:
<textarea ng-model="$parent.noticeText"></textarea>
Instead of
<textarea ng-model="noticeText"></textarea>
This issue happened to me while not using the ng-if directive on elements surrounding the textarea element. While the solution of Mathew is correct, the reason seems to be another. Searching for that issue points to this post, so I decided to share this.
If you look at the AngularJS documentation here https://docs.angularjs.org/api/ng/directive/textarea , you can see that Angular adds its own directive called <textarea> that "overrides" the default HTML textarea element. This is the new scope that causes the whole mess.
If you have a variable like
$scope.myText = 'Dummy text';
in your controller and bind that to the textarea element like this
<textarea ng-model="myText"></textarea>
AngularJS will look for that variable in the scope of the directive. It is not there and thus he walks down to $parent. The variable is present there and the text is inserted into the textarea. When changing the text in the textarea, Angular does NOT change the parent's variable. Instead it creates a new variable in the directive's scope and thus the original variable is not updated. If you bind the textarea to the parent's variable, as suggested by Mathew, Angular will always bind to the correct variable and the issue is gone.
<textarea ng-model="$parent.myText"></textarea>
Hope this will clear things up for other people coming to this question and and think "WTF, I am not using ng-if or any other directive in my case!" like I did when I first landed here ;)
Update: Use controller-as syntax
Wanted to add this long before but didn't find time to do it. This is the modern style of building controllers and should be used instead of the $parent stuff above. Read on to find out how and why.
Since AngularJS 1.2 there is the ability to reference the controller object directly instead of using the $scope object. This may be achieved by using this syntax in HTML markup:
<div ng-controller="MyController as myc"> [...] </div>
Popular routing modules (i.e. UI Router) provide similar properties for their states. For UI Router you use the following in your state definition:
[...]
controller: "MyController",
controllerAs: "myc",
[...]
This helps us to circumvent the problem with nested or incorrectly addressed scopes. The above example would be constructed this way. First the JavaScript part. Straight forward, you simple do not use the $scope reference to set your text, just use this to attach the property directly to the controller object.
angular.module('myApp').controller('MyController', function () {
this.myText = 'Dummy text';
});
The markup for the textarea with controller-as syntax would look like this:
<textarea ng-model="myc.myText"></textarea>
This is the most efficient way to do things like this today, because it solves the problem with nested scopes making us count how many layers deep we are at a certain point. Using multiple nested directives inside elements with an ng-controller directive could have lead to something like this when using the old way of referencing scopes. And no one really wants to do that all day!
<textarea ng-model="$parent.$parent.$parent.$parent.myText"></textarea>
Bind the textarea to a scope variable's property rather than directly to a scope variable:
controller:
$scope.notice = {text: ""}
template:
<textarea ng-model="notice.text"></textarea>
It is, indeed, ui-if that creates the problem. Angular if directives destroy and recreate portions of the dom tree based on the expression. This is was creates the new scope and not the textarea directive as marandus suggested.
Here's a post on the differences between ngIf and ngShow that describes this well—what is the difference between ng-if and ng-show/ng-hide.
I'm creating a custom Angular directive for a slide in menu which needs to watch a couple of attributes and one of those attributes needs to be two way bound to the main controller scope (sometimes). However, sometimes the attribute will not be added by the developer so it needs to be added automatically and set to the default (false). So, the directive can be used like this.
<slide-menu position="right" is-open="menuIsOpen"></slide-menu>
or like this:
<slide-menu></slide-menu>
When used the first way the main controller will be able to open and close the menu by changing the value of the boolean $scope.menuIsOpen.
When used without supplying the is-open attribute it should default to false and is obviously used internally and by a child toggle directive.
An additional complication is that whether the attribute is supplied by the developer or not it should exist in the DOM. so in the second example above the directive would set itself to false by default and add the attribute is-open="false" to the DOM?
The reason for requiring is-open="false/true" in the DOM at all times is that the menu is actually operated using CSS tansitions which use the following selector:
slide-menu[is-active="true"]{
// Slide the menu in using transforms/transitions
}
There is a jsfiddle here which shows how far I have got.
http://jsfiddle.net/jonhobbs/gEPvE/
Obviously it doesn't work, but it shows how I have tried to set a default and how I have tried to use # and & on the isolated scope for a one time binding (the menu position) and a 2 way bound expression for the is-open variable.
I'm clearly a long way from achieving what I need but any advice would really be appreciated.
Have a look at this fiddle http://jsfiddle.net/gEPvE/38/
I took the one you started and updated it to act like you specified.
You can make a two way binding value optional by adding a ? on the scope definition.
Like this
{
scope: {
'isOpen':'=?'
}
}
Now the is-open attribute is optional.
Then you can set the default value in the directive controller, like you had started to do.
Next, in order to synchronize the DOM attribute with the scope value you can use $watch.
$scope.$watch('isOpen', function(val) {
$element.attr('is-open', val);
});
Finally, I changed the second 'slideMenuToggle' directive to wrap/transclude its element in order to add an ng-click handler. This is mainly to avoid any nastiness with calling $scope.$apply yourself.
Let me know if that works for you.
EDIT
Answering your question in the comment, you can pass a value directly without having it be bound to the scope, you just need to wrap the value in quotes.
For example
<div ng-controller='ctrl'>
<hello world='imOnScope'></hello>
</div>
Assuming 'hello' is a directive with a scope of 'world': '=?' then angular will assign a reference to the parent scope's 'imOnScope' object to the directive's $scope.world member, allowing a two way binding scenario.
To just provide a value directly you may do something like this
<div ng-controller="ctrl">
<hello world="'directValue'"></hello>
</div>
In this scenario angular will just assign 'directValue' to the directive's $scope.world member.
You need to add ngTouch to your module.
var app = angular.module('app', ['ngTouch']);
And add this script:
http://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular-touch.js
The reason for requiring is-open="false/true" in the DOM at all times
is that the menu is actually operated using CSS tansitions which use
the following selector
Forcing directive attributes to be appropriate for css selectors is terrible idea. As you correctly stated, they are for developers. So add a class to the element dynamically.
It seems that you're misusing &, it would be ok to set up a callback, but since you don't do this, in its current state you can end up with one-way # with confidence.
I guess it can be something like this (just added ngTouch and ng-controller for parent scope).
You could replace
$scope.watch('isOpen', function () {
$element.toggleClass('opened', $scope.isOpen);
});
with
$scope.watch('isOpen', function () {
$attrs.isOpen = !!$scope.isOpen;
});
and get the behaviour you're asking for, easy as that. Ok, it is boolean now, and it reflects the scope, and you can use [is-open=true] selector. But guess what will happen with your binding? Broken. Fortunately, you can do
$scope.watch('isOpen', function () {
$element.attr('is-open', !!$scope.isOpen);
});
instead. Voila, we tricked Angular because it doesn't look after jqlite. But what will will happen with the binding when the directive will be re-compiled for any reason? Again, isOpen's binding is non-existing 'true' or 'false' scope variable. Broken.
So I am trying to bind inside a directive (to access outside) to a model inside of an ng-repeat. So in the outer controller I have a variable I would like to bind in like
//in the directive scope
filterArray: '='
Inside the directive that would be bound inside the directive to a model in an ng-repeat like so -
//inside the directive
<li ng-repeat="value in filter.values">
<input type="checkbox" ng-model="filterObject[filter.name][value]" ng-change="filterChange()">{{value}}
</li>
This worked fine until I changed the directive to have an isolate scope, now it is saying cannot set property of undefined. Is there any way to get this working as intended? The idea is the variable would build out when the user clicks the inputs so the outer controller would be able to see the built object.
Apologies if this is a bit confusing - I have made a fiddle to clarify : https://jsfiddle.net/vt1uasw7/42/ .
I want the outer controller to have access to the object built by binding the model - again this was working before I added the isolate scope. Thanks!
Edit: maybe the trick in this case is not to use the isolate scope? This one has me stumped, I've tried every combination of scope attributes :(.
If you can't pre-initialize your outter filterObject you can let the directive controller handle that for you:
$scope.filterArray[$scope.filter.name] = {};
And check your parameters as Claies stated, inside your directive you need to use filterArray and also the attribute name in the outter ng-repeat needs to be "filter-array and not "filterArray".
<div ng-repeat="filter in searchResults.filters" class="my-directive" filter="filter" filter-change="filterChange" filter-array="filterObject"> </div>
See this https://jsfiddle.net/vt1uasw7/164/
I want to change the ng-show condition using a java script function.
<span id="error1" ng-show="formerror"><font color="red">{{formerror}}</font></span>
I'm able to get the span attr using
var scope4 = angular.element($("#error1"))
You can do it, however I doubt this is very good idea to manipulate with internals of the Angular app from outside of it. But it's possible.
You don't need attribute, you just need to access the scope of the element and change formerror property of it. You can do it using scope method of the angular.element. For example:
var $scope = angular.element($("#error1")).scope();
$scope.formerror = 'Fill in required fields.';
$scope.$apply();
Demo: http://plnkr.co/edit/cmiQCgnxbvG4hrGY1c18?p=preview
Is it possible to bind a non-angular event to a $scope-Function?
I have a DIV. In this DIV, I'm not allowed to bind the ngClick-Event and I should bind the "customclick"-Event. So I tried the following but obviously this executes the function on $apply rather than telling the framework to use the function as the eventhandler:
<div id="myCustomDiv" customclick="{{ setSelectedTab() }}">
...
</div>
Is this even possible or can $scope-Functions only bind to angular-Directives? I could do it in the controller with $(element).bind but I'd rather have this part in the view where it belongs.
See How do I access the $scope variable in browser's console using AngularJS? for detailed examples of accessing $scope from non-Angular sources.
In your case, I believe the following will work:
<div id="myCustomDiv"
customclick="angular.element('#myCustomDiv').scope().setSelectedTab()">
...
</div>
This approach requires that you not run Angular in Production Mode so that you have access to the scope() function.