Call another controller from inside ng-repeat - angularjs

I am new to angular and I am trying to call a function from another Controller. I do not want to define an addIssue function in ItemsController which calls IssuesController.addIssue or share a service, but directly reference the IssuesController. Is there any way to do that?
Here is my sample code:
<div ng-controller="ItemsController">
<ul ng-repeat="item in items">
<li><a href ng-click="addIssue(item)">{{item.name}}</a></li>
</ul>
</div>
<div ng-controller="IssuesController">
<ul ng-repeat="issue in issues">
<li>{{issue.name}}</li>
</ul>
</div>
<script>
angular.module('app').controller("IssuesController", function () {
$scope.issues = [];
$scope.addIssue = function (item) {
// Add Issue
}
});
</script>
UPDATE:
What if I have a third base controller to help them share $scope, how will that work?
<div ng-controller="OrdersController">
<div ng-controller="ItemsController">
<ul ng-repeat="item in items">
<li><a href ng-click="addIssue(item)">{{item.name}}</a></li>
</ul>
</div>
<div ng-controller="IssuesController">
<ul ng-repeat="issue in issues">
<li>{{issue.name}}</li>
</ul>
</div>
</div>

As EliteOctagon mentioned, there are other and probably more "best practice" ways to achieve your goal but you can always do this the "dirty" way, you can use $rootScope in your ItemsController to call the addIssue(item) function on IssuesController, and since all other scopes are descendant scopes of the $rootScope you can use it in any controller.
Example: http://jsfiddle.net/choroshin/5YDJW/2/

There is, but it's such a terrible idea that you should think about it thoroughly. A much better solution would be to put that functionality into a parent controller. Obviously you have functionality that is much broader in scope (pun intended) then just that div with the IssuesController.
Provided your code is a realistic sample, then addIssue() is not even used there. So it wouldn't even make sense to put it there.
One way to directly access addIssue is:
angular.element(/*select your div*/).scope().addIssue(item);
How you select your div depends. If i has an id you can use that. If you use jQuery then you can use [ng-controller= ItemsController].

Why don't you nest the controllers? You can read the Scope Inheritance Example at http://docs.angularjs.org/guide/controller
<div ng-controller="ItemsController">
<ul ng-repeat="item in items">
<li><a href ng-click="addIssue(item)">{{item.name}}</a></li>
</ul>
<div ng-controller="IssuesController"> <!-- nested and will inherit scope -->
<ul ng-repeat="issue in issues">
<li>{{issue.name}}</li>
</ul>
</div>
</div>
so if you have a function in ItemsController
$scope.addIssue = function() {do something}
then the IssuesController will inherit the $scope and you'll be able to use that function.

Related

AngularJS - Change scope with one of the iterations of a ng-repeat

I have a project with Angular where I don't want to use a select element with ng-options, so I made up a list with different options in order to select one of them.
<div class="countrylist">
<ul>
<li ng-repeat="c in shippingCountry"><p>{{c.name}}</p></li>
</ul>
</div>
So the option selected would modify another element where the chosen option would be displayed.
<div>
<ul>
<li>{{selectedCountry}}</li>
</ul>
</div>
In order to do that, I would need to pass the data from the chosen option of the first element into the 2nd one. I have tried doing something like this
<li ng-repeat="c in shippingCountry" ng-click="selectedCountry = {{c}}"><p>{{c.name}}</p></li>
with no success.
You can check the plunker here Thanks in advance
I suggest you to use a function over there like this in the DEMO
<li ng-repeat="c in shippingCountry" ng-click="Click(c)"><p>{{c.name}}</p></li>
Having this method in your controller
$scope.Click=function (c)
{
$scope.select=c;
}
It creates child scope for each iteration, so explicitly refer parent scope:
Change like this,
<ul>
<li ng-repeat="c in shippingCountry" ng-click="$parent.selectedCountry = c"><p>{{c.name}}</p></li>
</ul>
DEMO
I've fixed your plunker here. It would be better to use methods in scope for this operations because they work in current scope, not in child
<li ng-repeat="c in shippingCountry" ng-click="selectCountry(c)">
<p>{{c.name}}</p>
</li>
// .html
<div>
<ul>
<li>{{selectedCountry.item}}</li>
</ul>
</div>
<div class="countrylist">
<ul>
<li ng-repeat="c in shippingCountry" ng-click="selectedCountry.item = c"><p>{{c.name}}</p></li>
</ul>
</div>
// controller
$scope.selectedCountry = {
item: $scope.shippingCountry[0]
};
Example

access variable in scope from ng-repeat ng-style

I got some problem on AngularJS.
my controller, mainCtrl, has this variables :
this.colors = {Sam:blue,Jane:red,Tom:pink};
this.arr = [{person:'Sam',story:'some story'},{name:'Tom',story:'some story2'}]
And I got this code :
<div ng-controller="mainCtrl as vm">
<ul ng-repeat="obj in arr">
<li ng-style={color:vm.color[obj.person]}>{{obj.story}}</li>
</ul>
</div>
I want that the li will be colored such as the color of the person at colors dictionary . how can I handle that? I got undefined every time, but when I do it explictly its work , for Example :
<li ng-style={color:vm.color['Sam']}>{{obj.story}}</li>
You are using the controllerAs-Syntax, so you must use vm.arr in your ng-repeat. And furthermore you should use the ng-repeat on the list item:
<ul>
<li ng-repeat="obj in vm.arr" ng-style="{color:vm.color[obj.person]}">{{obj.story}}</li>
</ul>
It should look like this.
<div ng-controller="mainCtrl as vm">
<ul>
<li ng-repeat="obj in vm.arr track by $index"
ng-style="{'color':vm.colors[obj.person]}"
ng-bind="obj.story">
</li>
</ul>
</div>
Remember to use your alias vm (controllerAs)
Usetrack by with ng-repeat for better performance.
I think that ng-repeat should have been placed in li
Her's a working jsfiddle http://jsfiddle.net/irhabi/nh4ddemr/

Expression in ng-if of AngularJS

Consider the following snippet
ng-if not working
<div class="row">
<div class="col-md-8">
<ul>
<li ng-repeat="bigL in bigLs">
<span ng-if="isObj(bigL)">{{bigL.note}}</span>
<ul ng-if="bigL instanceof Array">
<li ng-repeat="bigLl in bigL">
{{bigLl}}
</li>
</ul>
</li>
</ul>
</div>
</div>
ng-if working
<div class="row">
<div class="col-md-8">
<ul>
<li ng-repeat="bigL in bigLs">
<span ng-if="isObj(bigL)">{{bigL.note}}</span>
<ul ng-if="isArr(bigL)">
<li ng-repeat="bigLl in bigL">
{{bigLl}}
</li>
</ul>
</li>
</ul>
</div>
</div>
Controller
$scope.isArr = function(bigL){
return bigL instanceof Array;
};
I use ng-if to determine whether a nested ul is required to create (by determinate different data type inside the array bigLs), I come to a situation that ng-if cannot evaluate bigL instanceof Array, I then move this snippet inside a function, with the same context, the ng-of works properly, but still cannot understand why it is a need to wrap the expression inside a function instead of running it directly inside the ng-if.
Appreciate for any clarification, thanks!
I'm not exactly sure of the problem, but there are several things that have bad smells in your code:
Don't use 'instanceof Array', ever. It won't work in an angular expression.
Instead, use angular.isArray(). This will only work in javascript by adding a method to your scope.
So, you would want to do something like this:
Controller:
...
$scope.hasChildren = function(bigL1) {
return angular.isArray(bigL1);
}
Template:
...
<ul ng-if="hasChildren(bigL)">
...
As a bonus, it becomes much easier to unit test this code.

Angular Directive Best Practices - Is not using directive in Markup a good idea?

I've seen some examples where a div tag has a controller defined, but the directive is not:
<div ng-app="contestantApp">
<h1>Contestants</h1>
<section ng-controller="ContestantsCtrl as ctrl">
<ul>
<li ng-repeat="contestant in ctrl.contestants">
{{contestant.firstName}} {{contestant.lastName}}
</li>
</ul>
<myapp-contestant-editor-form contestants="ctrl.contestants">
</myapp-contestant-editor-form>
</div>
Is this bad practice implementing a controller without a directive? Are there situations this would be useful?
Thanks

Angular two different include inside controller have different $scope

<!-- index.html -->
<div ng-controller="navbarController">
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div ng-include src="'./html/bars.html'"></div>
<div ng-include src="'./html/extendBars.html'"></div>
</div>
</div>
<nav class="navbar navbar-default navbar-fixed-bottom" role="navigation">
<div class="container">
This is my cool bottom bar :)
</div>
</nav>
</div>
<!-- ./html/bars.html -->
<a class="navbar-brand" ui-sref="Welcome">Brand</a>
<ul class="nav navbar-nav">
<li ng-class="{ active: TopMenu=='OurWork'}" ng-click="TopMenu='OurWork'"><a ui-sref="OurWork">Our Work</a>
</li>
</ul>
<!-- ./html/extendBars.html -->
<ul class="nav navbar-nav">
<li ng-class="{ active: TopMenu=='ProjectManager'}" ng-click="TopMenu='ProjectManager'"><a ui-sref="ProjectManager">Projects Manager</a>
</li>
<li ng-class="{ active: TopMenu=='Publish'}" ng-click="TopMenu='Publish'"><a ui-sref="Publish">Publish</a>
</li>
<li>Logout
</li>
</ul>
The problem is that this two files that contain two part of navbar have different $scope, when i change value of TopMenu it changes only on one of two files. In my js controller code when i define $scope.TopMenu is defines correct on both files. Why this is happening?
ng-include creates a child scope. since you're using two ng-includes, a new child scope is created for each, both prototypically inheriting from the parent scope (the navbarController).
by prototypical inheritance, any objects on the parent will be seen in the child scopes (as long as a blocking object hasn't been created on the child). however, setting a value on the child scope won't be seen on the other child, as it's not part of it's inheritance chain (it only climbs directly up).
from the child scopes, you could access $rootScope instead of $scope in order to access the values above. alternately, you could encapsulate the data you're wanting to share between the scopes in a Service (in most cases, this is the preferred method to keep things clean).
EDIT to include function based approach based on question in comments:
instead of trying to directly set and access values on the parent scope, a quick alternative would be to create functions in your navbarController to handle this. a service is potentially cleaner, especially if you're using this from other areas in the app, but something like this should work (I didn't create a plnkr to test, and i obviously don't know what's in your existing navbarController -- so this is just a concept).
in your controller file:
.controller('navbarController', function($scope) {
var currentMenu = 'defaultMenuName';
$scope.setMenu = function(newMenu) {
currentMenu = newMenu;
};
$scope.isMenu = function(testMenu) {
return currentMenu == testMenu;
};
}
in your html:
<li ng-class="{ active: isMenu('OurWork')}" ng-click="setMenu('OurWork')"><a ui-sref="OurWork">Our Work</a>
Example of this approach in action:
http://plnkr.co/edit/eQKbjjRVdSqDjLlpLPCB?p=preview

Resources