Plunker is here:-
http://plnkr.co/edit/JaEi7ftnokYhdvBn4fRh?p=preview
I have emitted data and its available in $on() under data.name.
However, I am not able to display $scope.dumbevent1_name in UI using {{ dumbevent1_name }}
What am I doing wrong ?
Code:-
// Code goes here
angular.module('myapp', [])
.controller('mycontroller', mycontroller)
.component('semantic3', { // semantic3
restrict: 'E',
transclude: true,
template: `<h6> imsemantic3</h6> <div ng-transclude></div>
`,
controller: semantic3Controller,
})
.component('semantic2', { // semantic2
scope: {},
restrict: 'E',
transclude: true,
template: `<h6> imsemantic2</h6> <div ng-transclude></div>
`,
})
.component('semantic1', { // semantic1
scope: {},
restrict: 'E',
transclude: true,
template: `<h6> imsemantic1</h6> <div ng-transclude></div>
`,
})
.component('dumbCompDisplayNames', {
scope:true,
restrict: 'E',
template: `<h6>h6dumb1</h6> {{$ctrl.names}}`,
bindings:{
names : '<' //one-way data binding
},
controller: dumbController,
});
function semantic3Controller($scope, $element, $attrs){
var self = $scope;
$scope.$on('dumbevent1', function(event, data){
console.log(data.name); //works. received.
self.dname = data.name;
$scope.dumbevent1_name = data.name; //works
// console.log($scope.dumbevent1_name); //works
// capturename( data); //works
});
// console.log($scope.dumbevent1_name); //doesnt work.
// function capturename(x){
// $scope.dumbevent1_name = x.name;
// console.log($scope.dumbevent1_name); //works
// }
}
function dumbController($scope, $element, $attrs){
// console.log($scope); //works. these r NOT positional injection
// console.log($element);
// console.log($attrs);
$scope.$emit('dumbevent1', {name: 'namedumb1'});
}
// main controller
function mycontroller(){
console.log('i am mycontroller');
}
The time wasted on commenting repeatedly is worthwhile somehow?? If don't have time to look at the plunker don't waste time commenting. Like I said I fixed the issue.
Related
export function triMenuItemDirective() {
var directive = {
restrict: 'E',
require: '^triMenu',
scope: {
item: '='
},
// replace: true,
template: require('./menu-item-dropdown.tmpl.html'),
controller: triMenuItemController,
controllerAs: 'triMenuItem',
bindToController: true
};
return directive;
}
I need to load different html depending on item.
With the old way you could do:
template: '<div ng-include="::triMenuItem.item.template"></div>',
And in Controller
triMenuItem.item.template = 'app/components/menu/menu-item-' + triMenuItem.item.type + '.tmpl.html';
How do I achive this with webpack?
Something like
template: require('./menu-item-{{triMenuItem.item.type}}.tmpl.html'),
I think that to do this, you have at least three different approaches:
1- Use $templateCache and then pass a string variable to ng-include
.directive('myDirective', ['$templateCache', function ($templateCache) {
return {
scope: {
item: '='
},
template: '<div ng-include="content"></div>',
link: function (scope) {
$templateCache.put('a.tpl.html', require('./a.html'));
$templateCache.put('b.tpl.html', require('./b.html'));
scope.content = (scope.item === 'a') ? 'a.tpl.html' : 'b.tpl.html';
}
}
}]);
2- Use ng-bind-html.
app.directive('myDirective', ['$sce', function ($sce) {
return {
scope: {
item: '='
},
template: '<div ng-bind-html="content"></div>',
link: function (scope) {
if(scope.item === 'a')
scope.content = $sce.trustAsHtml(require('./a.html'));
}
}
}]);
3- Use ng-if. Maybe the less dynamic solution of the three, but is pretty simple if your requirements let you do it.
app.directive('myDirective', function () {
return {
scope: {
bool: '='
},
template: `
<div>
<div ng-if="item === 'a'">${require('./a.html')}</div>
<div ng-if="item === 'b'">${require('./b.html')}</div>
</div>
`
}
});
I'm relatively new to AngularJS and working on creating tabs in a page. Till now I have resolved my problems with angularjs by searching a lot on internet but I can't resolve this. Hope anyone can help me with ideas and better knowledge of angularjs.
I have two custom directives tabset and tab. 'Tabset' is the directive to maintain the tabs and 'tab' is for a single tab.
app.directive('tabset', function() {
return {
restrict: 'E',
transclude: true,
templateUrl: 'tabset.html',
bindToController: true,
scope: {},
controller: function($scope){
$scope.tabs = [];
this.addTab = function(tab) {
$scope.tabs.push(tab);
}
console.log("In tabset controller");
},
link : function(scope){
console.log("In the tabset link");
}
}
});
//Custom Directive for the tab controls
app.directive('tab', function() {
return {
restrict: 'E',
transclude: true,
template: '<h2>Welcome to Stackoverflow</h2> <div role="tabpanel" ng-transclude></div>',
require : '^tabset',
scope: {},
link : function(scope, elem, attr, tabsetCntrl) {
tabsetCntrl.addTab(scope);
console.log("In the tab link");
}
}
});
I call these directives in my HTML page as shown below:
<tabset>
<tab>
This is one tab
</tab>
<tab>
This is another tab
</tab>
</tabset>
But, when I run the code, the link function of the tab directive is not running. The 'require : ^tabset' option gets the controller from the tabset, but the link function of the tab directive is not working.
Try adding controllerAs: '$ctrl' to your tabset directive.
Like:
angular.module('app').directive('tabset', function() {
return {
restrict: 'E',
transclude: true,
templateUrl: 'tabset.html',
bindToController: true,
controllerAs: '$ctrl', // <---- HERE
scope: {},
controller: function($scope){
$scope.tabs = [];
this.addTab = function(tab) {
$scope.tabs.push(tab);
}
console.log("In tabset controller");
},
link : function(scope){
console.log("In the tabset link");
}
}
});
Tested
Further info found by checking the error seen in console here
Prudhvee, take a look at this demo i did to understand the making of angular tabs using nested directives.
app.directive('tabset', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
controller: [ "$scope", function($scope) {
var panes = $scope.panes = [];
$scope.select = function(pane) {
angular.forEach(panes, function(pane) {
pane.selected = false;
});
pane.selected = true;
}
this.addPane = function(pane) {
if (panes.length == 0) $scope.select(pane);
panes.push(pane);
}
}],
template:
'<div class="tabbable">' +
'<ul class="nav nav-tabs">' +
'<li ng-repeat="pane in panes" ng-class="{active:pane.selected}">'+
'{{pane.title}}' +
'</li>' +
'</ul>' +
'<div class="tab-content" ng-transclude></div>' +
'</div>',
replace: true
};
});
app.directive('tab', function() {
return {
require: '^tabset',
restrict: 'E',
transclude: true,
scope: { title: '#' },
link: function(scope, element, attrs, tabsCtrl) {
tabsCtrl.addPane(scope);
},
template:
'<div class="tab-pane" ng-class="{active: selected}" ng-transclude>' +
'</div>',
replace: true
};
})
http://plnkr.co/edit/BJWWw2?p=preview
This should not be too hard a thing to do but I cannot figure out how best to do it.
I have a parent directive, like so:
directive('editableFieldset', function () {
return {
restrict: 'E',
scope: {
model: '='
},
replace: true,
transclude: true,
template: '
<div class="editable-fieldset" ng-click="edit()">
<div ng-transclude></div>
...
</div>',
controller: ['$scope', function ($scope) {
$scope.edit = ->
$scope.editing = true
// ...
]
};
});
And a child directive:
.directive('editableString', function () {
return {
restrict: 'E',
replace: true,
template: function (element, attrs) {
'<div>
<label>' + attrs.label + '</label>
<p>{{ model.' + attrs.field + ' }}</p>
...
</div>'
},
require: '^editableFieldset'
};
});
How can I easily access the model and editing properties of the parent directive from the child directive? In my link function I have access to the parent scope - should I use $watch to watch these properties?
Put together, what I'd like to have is:
<editable-fieldset model="myModel">
<editable-string label="Some Property" field="property"></editable-string>
<editable-string label="Some Property" field="property"></editable-string>
</editable-fieldset>
The idea is to have a set of fields displayed by default. If clicked on, they become inputs and can be edited.
Taking inspiration from this SO post, I've got a working solution here in this plunker.
I had to change quite a bit. I opted to have an isolated scope on the editableString as well because it was easier to bind in the correct values to the template. Otherwise, you are going to have to use compile or another method (like $transclude service).
Here is the result:
JS:
var myApp = angular.module('myApp', []);
myApp.controller('Ctrl', function($scope) {
$scope.myModel = { property1: 'hello1', property2: 'hello2' }
});
myApp.directive('editableFieldset', function () {
return {
restrict: 'E',
scope: {
model: '='
},
transclude: true,
replace: true,
template: '<div class="editable-fieldset" ng-click="edit()"><div ng-transclude></div></div>',
link: function(scope, element) {
scope.edit = function() {
scope.editing = true;
}
},
controller: ['$scope', function($scope) {
this.getModel = function() {
return $scope.model;
}
}]
};
});
myApp.directive('editableString', function () {
return {
restrict: 'E',
replace: true,
scope: {
label: '#',
field: '#'
},
template: '<div><label>{{ label }}</label><p>{{ model[field] }}</p></div>',
require: '^editableFieldset',
link: function(scope, element, attrs, ctrl) {
scope.model = ctrl.getModel();
}
};
});
HTML:
<body ng-controller="Ctrl">
<h1>Hello Plunker!</h1>
<editable-fieldset model="myModel">
<editable-string label="Some Property1:" field="property1"></editable-string>
<editable-string label="Some Property2:" field="property2"></editable-string>
</editable-fieldset>
</body>
You can get access to parent controller by passing attribute in child directive link function
link: function (scope, element, attrs, parentCtrl) {
parentCtrl.$scope.editing = true;
}
Correct me if I am wrong, but I think in the firstDirective scenario, I am unable to achieve the behavior of the secondDirective because it's creating a sibling scope; I am unable to access the template's controller's scope. I want the behavior of the secondDirective with the power of transclusion. Is there a way to achieve this? or am I attacking this problem the wrong way?
http://jsfiddle.net/3QRDt/68/
var app = angular.module('myApp', []);
app.directive('firstDirective', function(){
return {
restrict: 'EA',
replace: true,
scope: true,
transclude: true,
template: '<div id="holder" data-ng-controller="MyController">{{shouldBeOpen}}<div ng-transclude></div><button data-ng-click="close()">Close</button></div>',
link: function(scope, element) {
scope.openDirective = function() {
scope.open()
alert("Hello from Directive")
}
scope.hello ='dad'
}
};
})
.directive('secondDirective', function(){
return {
restrict: 'EA',
replace: true,
scope: true,
transclude: true,
template: '<div id="holder" data-ng-controller="MyController">{{shouldBeOpen}}<button data-ng-click="openDirective()">{{hello}} Open</button><button data-ng-click="close()">Close</button></div>',
link: function(scope, element) {
scope.openDirective = function() {
scope.open()
alert("Hello from Directive")
}
scope.hello ='dad'
}
};
});;
app.controller('MyController', ['$scope', function($scope) {
$scope.shouldBeOpen = false
$scope.close = function() {
$scope.shouldBeOpen = false
}
$scope.open = function() {
$scope.shouldBeOpen = true
alert("Hello from Controller")
}
}]);
You can use $$prevSibling to reference from the transcluded scope to the isolated scope created by the directive:
<button data-ng-click="$$prevSibling.openDirective()">{{hello}} Open</button>
Here is the code, ideally i should see
parent: true
when I click the toggle
However, it doesn't work
Here is the plunker
<body ng-controller="MainCtrl">
<button type="button" ng-click='isParentShown= !isParentShown' >Toggle</button>
<div><span>Controller-isParentShown: {{isParentShown}}</span></div>
<parent isShown='isParentShown'></parent>
</body>
var app = angular.module('plunker', []).directive('parent',function(){
return {
restrict: 'E',
replace: true,
scope: {
isShown: '='
},
template: '<span>Parent: {{isShown}}</span>'
};
}).directive('child',function(){
return {
restrict: 'E',
replace: true,
template:'<span>Child: {{isChildShown}}</span>',
scope: {
isChildShown: '#'
}
};
});
app.controller('MainCtrl', function($scope) {
$scope.isParentShown = false;
});
The problem is in the casing of the attributes, if you define a isShown binding, it's expecting a is-shown or is:shown attribute. Here's the fixed plunker: http://plnkr.co/edit/UOigth