Angular 1.5.8 Component, get parent context in ng-repeat - angularjs

I am creating a dynamic menu with ng-click action template is configured in DB.
<ul class="dropdown-menu dropdown-menu-right" id="widget-{{$ctrl.id}}-context-menu">
<li ng-repeat="Menu in $ctrl.menu">
{{Menu.Name}}
</li>
</ul>
How can I get reference to the parent context from ng-repeat so that I can parse the template string (eg. '$ctrl.handleClick('abc')') to make a click event? $parent and $ctrl are not working inside ng-repeat.
What is the correct way to convert a string to an ng-click event?
What should I do in

The $scope with components is always isolated, I am not sure you can access it that way and you shouldn't. What you need to do is bind the function from your parent controller/component.
Bind the function from the parent: ($ctrl is the parent here)
<my-component action="$ctrl.evaluateFn">
Add the binding to your component:
bindings: {
action: '&'
}
Use it in your markup:
<ul class="dropdown-menu dropdown-menu-right" id="widget-{{$ctrl.id}}-context-menu">
<li ng-repeat="Menu in $ctrl.menu">
{{Menu.Name}}
</li>
</ul>
You can use whatever you want instead of action.
https://docs.angularjs.org/guide/component

Related

UI-Router ui-sref-active throws error when using ui-sref params

I've got a Bootstrap navbar dropdown menu, where clicking the parent link produces the dropdown list (default behaviour). The dropdown list of the parent is built using ngRepeat from an array of navigation data, and each has a ui-router state parameter, so it looks like:
<li class="dropdown">
<a href class="dropdown-toggle" data-toggle="dropdown">
Parent Link
</a>
<ul class="dropdown-menu" role="menu">
<li ng-repeat="item in navCtrl.items()"
ui-sref-active="active">
<a ui-sref="some.state({ paramKey: paramValue })">
{{item.link}}
</a>
</li>
</ul>
</li>
But, even though it does seem to drop the active class on my link it throws this error in the console:
TypeError: Cannot read property 'name' of undefined
I am not entirely sure about the answer, but, as far as I know, why would you use navCtrl.items() using brackets? I have never seen it used like that before. Wouldn't the old item in items ng-repeat work? Sorry if it does not help at all.

Submit and disable all buttons in an ng-repeat without adding a new property on the scope

I have a list of items where each item is clickable and should trigger the submit(id) function. I would like to disable all items (buttons) when one of them is clicked.
<ul>
<li ng-repeat="item in items">
<button ng-click="submit(item.id)">Submit</button>
</li>
</ul>
I could define $scope.submitted variable in a controller and then set ng-disabled="submitted" in my view. I could also wrap it into a <form> and use frm.$submitted. Well... I would like to define everything inside view.
I search for an elegant solution where a don't have to define a $scope variable to achieve this. What do you propose?
If you do not want to define a property in the controller, and assuming that submit function never fails to submit. You could utilize the items array itself, by adding a property when click happens and after submit function is run.
<ul>
<li ng-repeat="item in items">
<button ng-click="submit(item.id); items.submitted=true"
ng-disabled="items.submitted">Submit</button>
</li>
</ul>
With this you are adding a property in the array items (so that it is available across child scopes of ng-repeat as well as items is set on its parent scope) so essentially you are not defining a new scope variable for this.
angular.module('app',[]).controller('ctrl', function($scope){
$scope.items = [{id:1},{id:2},{id:3},{id:4}]
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<ul>
<li ng-repeat="item in items">
<button ng-click="submit(item.id); items.submitted=true"
ng-disabled="items.submitted">Submit</button>
</li>
</ul>
</div>

ui-router active class for parent menu when submenu selected

I am a newbie to ui-router , i would like to get a menu like below (its not a collapse thing, please see the plnkr )
menu1
a) submenu1
b) submenu2
c) submenu3
menu2
menu3
I managed to get the menus and submenus using the ui-router but not sure about the proper way to use the ui-router and used ui-sref-active="active" active the menu , the problem am facing is when I click on the submenu i would like to get the active to parent also.. ie if I click submenu1 , submenu2 or submneu3 i want to active its parent menu1.
here is the plunker : http://plnkr.co/edit/1kpmUiacrb3Aoo4E19O1?p=preview
There is an updated plunker, which does use the $state.includes method as defined here
Angular UI Router: How do I get parent view to be "active" when navigating to nested view?
the changes are: menu gets controller which puts $state into $scope:
"menu#dashboard": { templateUrl: "menu.html",
controller : function ($scope, $state){ $scope.$state = $state },
},
instead of this:
<li ui-sref-active="active"><a ui-sref=".menu1.submenu1">Menu 1</a></li>
<li ui-sref-active="active"><a ui-sref=".menu2">Menu 2</a></li>
<li ui-sref-active="active"><a ui-sref=".menu3">Menu 3</a></li>
we have to use defintion with ng-class:
<li ng-class="{active:$state.includes('dashboard.menu1')}"><a ui-sref=".menu1.submenu1">Menu 1</a></li>
<li ng-class="{active:$state.includes('dashboard.menu2')}"><a ui-sref=".menu2">Menu 2</a></li>
<li ng-class="{active:$state.includes('dashboard.menu3')}"><a ui-sref=".menu3">Menu 3</a></li>
BUT: this feature would be in a next ui-router release as we can see here:
feat(uiSrefActive): Also activate for child states.
cite
To limit activation to target state use new ui-sref-active-eq directive
Breaking Change: Since ui-sref-active now activates even when child states are active you may need to swap out your ui-sref-active with ui-sref-active-eq, thought typically we think devs want the auto inheritance.

Uncertainty about the use of ngInclude

I render recursive template with ngInclude. Here is my code:
<!--
definitionsRenderer.html
-->
<ul data-ng-if="currentLoc.definitions && templateIsloaded">
<li ng-repeat="definition in currentLoc.definitions">
{{definition.text}}
</li>
</ul>
<ul data-ng-if="templateIsloaded">
<li ng-repeat="loc in currentLoc.loc" ng-include="'./partials/definitionsRenderer.html'"></li>
</ul>
I need code to be executed asynchronous. So for scope of every included template
I want to have a variable - templateIsloaded with value false by default. When template is loaded and rendered it value to be true. How do that?
Best regards.
To have separate $scope for each of recursive called includes you can simply add ng-controller.
<li ng-repeat="loc in currentLoc.loc" ng-controller="definitionsRendererCtrl" ng-include="'./partials/definitionsRenderer.html'"></li>

Call another controller from inside ng-repeat

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.

Resources