I have written an angular function that works fine. Now, I want to write another angular function that calls the first function. How can I do this?
app.controller("AppCtrl",function($scope,$location,$http,$compile,$rootScope){
$scope.func1 = function(param1,param2){
... // function body
};
$scope.func2 = function(param3) {
var value = "someValue";
$scope.func1(value,param3);
};
});
Unfortunately func2() doesn't work, even though fucn1() works if I call it directly (e.g., <div ng-click="func1(val1,val2)">Click Here</div>. Why?
UPDATE:
It's because I'm doing the following:
<ul>
<li ng-click="func2('{{item.value}}') ng-repeat="item in items">Item</li>
</ul>
For some reason {{item.value}} is not being compiled in the ng-repeat. I can inspect the HTML and see that the values are there, but the ng-click doesn't do anything. However, if I manually enter a value for the parameter in func2, then it works. So, now my questions is: How do I compile items in an ng-repeat?
I fixed your example here: http://jsfiddle.net/CsffM/
The problem is that you are using brackets in your expression,
Insted, do this:
<li ng-click="func2(item.value)" ng-repeat="item in items">Item</li>
I hope I have helped!
Related
I've an array and I'm looping over this array and calling a function into this ng-repeat and this function is in link function of a directive
so my problem is, ng-repeat looping only twice (length of array items) but calling directive link function more than twice
Here my code snippet
link:function(scope){
$scope.test = function() {
console.log('sssss');
}}
and template is
<div ng-repeat ="item in items> {{test()}}></div>
please help me to prevent calling test function more than items length.
You should do this,
<div ng-repeat ="item in items" ng-init="test()"> </div>
Reason test() is getting called more times than length of array items is
because of this {{test()}}.
AngularJS registers a watcher for {{}}(binding) in view.
This watcher keeps track of whether value has been changed or not(it compares the old value to new value). watcher's expression(in your case, test()) gets evaluated atleast once in this process.
You can read more about it here.
Thats the reason your test() is getting more number of times than length of array.
<div ng-repeat ="item in items" ng-init="test()"> </div>
If you use ng-init, test() will only be initialized(called) once per each repeat.
I have an AngularJS controller with the following function:
$scope.getExampleValue = function(exampleId) {
// calculate a value using underscore's _.where()
// clause against two JSON arrays on the $scope
// and the exampleId parameter passed in
return computedValue;
}
The function's parameter (exampleId) is rendered from the server, so the resulting HTML looks like this:
<div ng-controller="ExampleController">
...
<span>{{ getExampleValue(3) }}</span>
<span>{{ getExampleValue(4) }}</span>
<span>{{ getExampleValue(5) }}</span>
...
</div>
The problem I have is that AngularJS doesn't know to call getExampleValue() again when the JSON arrays used in the function have changed: they're 2 simple JSON arrays, new JSON items can be added or removed, or properties of existing JSON items in either array can be modified which affect the result.
I've looked at $scope.watch() and $scope.watchCollection() but I'm unsure how I can use them without changing my approach to bind against already computed values rather than against the function I prefer.
Essentially I think I'm asking how to notify AngularJS that a complicated bound value has changed, then I could wrap that notification up in a $scope.watch()..
Thanks for your help.
You are looking for $scope.$apply:
When you change the JSON asyncly, run:
$scope.$apply(function () {
// update the properties on $scope
});
Alright so I found out what might be my solution for a task I am trying to accomplish: to use some sort of toggle feature which I have seen represented a couple of different ways in other questions here on Stack Overflow. However, mine is a bit of a special case that I can't seem to figure out how to adjust to get it to work.
Here is the accordion where the text needs to appear:
<div ng-controller="Ctrl">
<accordion id="myID">
<accordion-group heading="My Heading">
{{toggleText}}
</accordion-group>
</accordion>
</div>
The text that needs to appear depends on what is clicked however:
<area ng-repeat="x in Object" alt="{{x.name}}" title="" ng-click="thisClick(x.name,x.address);toggle = !toggle" shape="poly" coords="{{x.htmlcoords}}" />
I have an image that has hot spots on it. I used ng-click="thisClick(x.name,x.address)" to easily capture the data from my Object and I was able to alert it in my thisClick(name,address) function. This part of the HTML is in a div that separately calls the same controller as the one above, I don't know if that would be relevant. I couldn't get my code working before trying this toggle stuff unless I kept the controller where it was and just called it again. Anyway, now to apply the toggle feature I tried changing the ng-click to what is shown above and the function to:
$scope.thisClick = function(name,address){
$scope.toggle = true;
$scope.$watch('toggle',function(){
$scope.toggleText = $scope.toggle ? '' : name+address;
});
};
Ultimately the name and address won't be squished together but this is for testing purposes only.
When I run the code, simply put nothing happens.
Either there is a way to clean this up or a way to approach this entirely differently? I hope I provided enough information.
I wish it were as simple as:
<area ng-repeat="x in building" alt="{{x.name}}" title="" ng-click="thisBuilding = x.name+x.address" shape="poly" coords="{{x.htmlcoords}}" />
$scope.buildingName = name;
$scope.buildingAddress = address;
$scope.thisBuilding = function(){
return $scope.buildingName + " " + $scope.buildingAddress;
};
};
:
{{thisBuilding()}}
This sounds quite a lot like a scope issue. As ng-repeat creates a new child scope for each item, most likely you end up setting the $scope.toggleText property in "wrong" scope, i.e. not in the scope of accordion-group where you are trying to display the property.
You might want to play around a bit with some Angular inspector tool, for example ng-inspector to verify this.
If the problem indeed is with toggleText property ending up in the wrong child scope, one possible workaround could be introducing a container object for the property in the root scope. The reason why this could work is that objects are passed as references for child scopes, not as copies like primitive properties are. A whole lot more on this topic can be read from Understanding Scopes article in AngularJS wiki.
So, something along these lines, starting from controller Ctrl:
// inside the controller code:
// initialize the toggleContainer object
$scope.toggleContainer = {};
Then in html template:
<div ng-controller="Ctrl">
<accordion id="myID">
<accordion-group heading="My Heading">
{{toggleContainer.text}}
</accordion-group>
</accordion>
</div>
And finally in the thisClick function, store the value you want to property toggleContainer.text instead of simple toggleText:
$scope.thisClick = function(name,address){
$scope.toggle = true;
$scope.$watch('toggle',function(){
$scope.toggleContainer.text = $scope.toggle ? '' : name+address;
});
};
I have the follow code:
<li class='' ng-click="changeStatus('hello', '{{result.name}}')">
Where 'hello' is my first parameter for changeStatus and I want to pass of binded result.name's value as the second parameter. Does anyone know how to accomplish this?
I tried {{result.name}}, '{{results.name}}' but neither seems to work.
There is probably something simple that am I missing?
I took a look at:
Can you pass parameters to an AngularJS controller on creation?
but both the parameters in ng-init were string literals.
You don't have to pass it.
You could just access it in your controller using :
$scope.result.name
If results is an array and you want to pass an individual result to a controller click function you need not decorate it with curly braces. The li will look like this:
<li ng-repeat="result in results" ng-click="changeStatus('hello', result.name)">{{result.name}}</li>
Working Fiddle
Angular treats the content of ng-click as an expression. This means that you write the content as though it is plain javascript (in most cases). For your example, this means leaving out the curly braces (since you are already writing 'javascript').
<li class='' ng-click="changeStatus('hello', result.name)">
I'll try to explain the problem with the example. Example is simplified, so it's not very logical, but anyway..
Let's say I have such view
<div ng-app="TestApp" ng-controller="MyController">
<button ng-add-item="items">Add Item</button>
<ul>
<li ng-repeat="item in items">{{item.name}} <button ng-change-item="item">Change item</button></li>
</ul>
</div>
And I have two directives:
1) ngAddItem - which adds dummy item (after click)
2) ngUpdateItem - which changes item (after click)
The problem is that 1) works great, but second - not..
http://jsfiddle.net/pbmnL/2/
P.S. I know I can use ng-click and many other things in this example. This is just simplified example.
Thanks for a help!..
UPDATE: If I change just a name property everything works fine!
http://jsfiddle.net/pbmnL/4/
But in real example I still need to change entire object..
Your code does not work because with this line:
_item = _changed_item;
you just point local variable _item to another object but do not update the item in the list.
As a solution you may use angular.copy - it replaces all properties of one object with properties from another one.
angular.copy(_changed_item, _item);
Here is jsfiddle that works.
Do this:
$element.bind('click', function () {
$scope.$parent.item.name = 'changed name';
$scope.$apply();
});