Why does not work two bind way in directive Angular JS? - angularjs

I use directive:
return {
restrict: 'E',
scope: {
isread: "=isread"
,....
templateUrl: 'list.html',
Where list.html is:
<span ng-show="isread"></span>
And parent trmplate from where I call directive:
<div class="top-menu" ng-controller="NotificationController">
<notification-list isread="is_read"></notification-list>
</div>
And NotificationController:
scope.makeRead = function() {
$scope.is_read = true;
}
Why when I change $scope.is_read = true; in controller it is not changed in directive in variable isread?

return {
restrict: 'E',
scope: {
isread: "="
,....
templateUrl: 'list.html',

Related

How to use require (webpack) with dynamic string, angularjs

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>
`
}
});

Communicate between custom directives in angularJS

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

AngularJS directive: scope with named controller

I have the example below.
HTML:
<body ng-controller="MainCtrl as MgtCtrl">
<p>Hello {{MgtCtrl.name}}!</p>
<p>Result is {{MgtCtrl.result}}!</p>
<output-content data="MgtCtrl.name" result="MgtCtrl.result"></output-content>
</body>
JavaScript:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
var MgtCtrl = this;
MgtCtrl.name = 'World';
MgtCtrl.result = "no";
MgtCtrl.changeLabel = function() {
alert('changeLabel');
MgtCtrl.result = 'yes';
}
});
app.directive('outputContent', function() {
return {
restrict: 'E',
replace: true,
templateUrl: 'outputContent.html',
scope: {
data: '=',
changeLabel: '&',
result: '='
},
controller: 'MainCtrl',
controllerAs: 'MgtCtrl'
};
});
ouputContent.html:
<div>
{{data}}
<button ng-click="MgtCtrl.changeLabel()">Change</button>
</div>
Plunker is: http://plnkr.co/edit/BW8VDyCaRnRgxE8I9JJy
I would like the result to be 'yes' when I click on the 'Change' button.
It doesn't work because of the named controller.
Could you please explain to me how to write the directive to do so ?
Regards.
You never was binding the scope variables to the named controller in the directive.
You must add the attribute bindToController: true to the directive definition like this plunker:
http://plnkr.co/edit/2QdnkpeuTM6adG9KoyJT?p=preview
Directive code:
app.directive('outputContent', function() {
return {
restrict: 'E',
replace: true,
templateUrl: 'outputContent.html',
scope: {
data: '=',
changeLabel: '&',
result: '='
},
controller: 'MainCtrl',
controllerAs: 'MgtCtrl',
bindToController: true
};
});
This go to add the data and result binding to the respective directive controller.
I think in this case you don't need to specify controller in the directive.
app.directive('outputContent', function() {
return {
restrict: 'E',
replace: true,
templateUrl: 'outputContent.html',
scope: {
data: '=',
changeLabel: '&',
result: '='
}
};
});
Also html shoul be updated:
<body ng-controller="MainCtrl as MgtCtrl">
<p>Hello {{MgtCtrl.name}}!</p>
<p>Result is {{MgtCtrl.result}}!</p>
<output-content data="MgtCtrl.name" result="MgtCtrl.result" change-label="MgtCtrl.changeLabel()"></output-content>
</body>

How can I pass a template to a directive in an attribute?

I want to pass a template to a directive like this:
<my-directive template="/templates/my-directive-template.html"></my-directive>
If no template is provided then the standard template is used.
How can I achieve this?
Or shouldn't I do this? I just want to reuse a directive, but want to give it different appearances each time.
Here's the directive... but I'm stuck on how to move forward.
app.directive('my-directive', function(){
return {
restrict: 'E',
scope: {
template: '=template'
},
template: 'standard-template.html'
}
})
templateUrl can be a function, that gets the element and its attributes as arguments. So you can do the following:
app.directive('my-directive', function(){
return {
restrict: 'E',
templateUrl: function(element, attrs) {
return attrs.template || 'standard-template.html';
}
You could use ng-include. So as an example
app.directive('my-directive', function(){
return {
restrict: 'E',
scope: {
template: '=?'
},
template: '<div ng-include="directiveTemplate"></div>',
link: function (scope) {
scope.directiveTemplate = scope.template || '/path/to/default.tpl.html';
}
}
})

AngularJS - accessing parent directive properties from child directives

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;
}

Resources