Reputation: 4435
Plunker, because the snippet editor isn't liking me today.
I'm working on using .component()
in place of .directive()
when using Angular 1.6 to get myself more into the type of design pattern used by Angular 2. The issue is that I cannot use any references to either $tabs
or $tab
(the controllers for those respective components). Nothing is output by using either {{$tab.tabsCtrl.nothing}}
or {{$tabs.nothing}}
.
Please Note:this is not my actual scenario, but it does share a common problem with what I am actually doing.
I've searched around and I get a lot of results for the Angular 2 components, but if I am being honest reading through it is basically Greek.
// Code goes here
angular.module('main.app', [])
.component('tabs', {
controller: function($http) {
this.tabs = [];
this.nothing = 'nada';
this.addTab = function(tab) {
this.tabs.push(tab);
}; //end addTab
this.selectTab = function(tab) {
this.tabs.map(function(item) {
item.selected = false;
});
var selected = this.tabs.filter(function(item) {
return item === tab;
});
if (selected.length) selected[0].selected = true;
}; //End selectTab
},
template: '<ul class="nav nav-tabs nav-justify justify-content-center"><li class="nav-item" ng-repeat="tab in $tabs.tabs" ><a href="#" ng-click="$tabs.selectTab(tab)" class="nav-link" ng-class="{\'active\':tab.selected}">{{tab.tabTitle}}</a></li></ul><div class="tabs-content" ng-transclude></div>',
transclude: true,
controllerAs: '$tabs'
})
.component('tab', {
require: {
'tabsCtrl': '^tabs'
},
bindings: {
'tabTitle': '@',
'selected': '<'
},
controller: function() {
this.$onInit = function() {
this.selected = this.selected || false;
this.tabsCtrl.addTab(this);
}; //end $onInit
},
transclude: true,
controllerAs: '$tab',
template: '<div class="tab" ng-show="$tab.selected"><div ng-transclude></div></div>'
})
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.js"></script>
<tabs>
<tab tab-title="First Tab" selected="true">
<div class="jumbotron">
<h3>Lorem ipsum.</h3>
<p class="lead">Lorem ipsum dolor sit amet.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iusto, in!</p>
</div>
some other text
</tab>
<tab tab-title="Second Tab">
<strong>With a header!</strong>
<div class="row">
<div class="col-6 bg-primary">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nisi, quam, quod, optio qui cum rerum vel eos rem aspernatur quia maxime incidunt numquam ipsum eum neque dicta distinctio. Minus, itaque.</div>
<div class="col-6 bg-danger">Reprehenderit, numquam, rerum, reiciendis neque adipisci provident ea quo illo praesentium inventore fuga quisquam ducimus? Ipsum, autem, illo ullam corporis incidunt ad labore accusantium tempora officia quas quia eaque facere.</div>
</div>
</tab>
<tab tab-title="Potato Tab">
<h3>Big books {{$tabs.nothing||'nah'}}</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iste quos assumenda vero fugiat officia pariatur consequatur deserunt quisquam veniam nemo?</p>
<p>Fugiat, error, impedit, accusantium consequuntur beatae facere esse voluptatum enim animi porro commodi modi cupiditate aliquam iure ipsa. A, officiis!</p>
<p>Architecto velit quod explicabo laborum reprehenderit culpa tempora facilis minima eum. Natus aliquid eaque laboriosam accusamus dolor hic similique ad.</p>
</tab>
</tabs>
Thanks, just in case I forget to say it in the future!
Upvotes: 0
Views: 318
Reputation: 38490
The transcluded scope will be a child scope of the directive's isolate scope.
Since components use isolate scopes, you can't make use of prototypal inheritance by just doing {{$tabs.nothing}}
. It would work if $tabs
was exposed via $rootScope
however, or any other non-isolate scope above tabs in the hierarchy (only ng-app
in your example, so only $rootScope
).
You can walk the scope chain manually.
Based on your example:
tab
directive$parent
would be the isolate tab
scope$parent
would be the transcluded child scope of the tabs
directive$parent
would be the isolate tab
scopeThis gives:
{{$parent.$parent.$parent.$tabs.nothing}}
Demo: http://plnkr.co/edit/jpTGVKWKEQlmGYpaeqtZ?p=preview
In most cases this isn't really a feasible solution. Probably better to expose the functionality that the transcluded content needs via a service.
Hard to give a better solution without knowing the real use case.
Upvotes: 1