ng-click attribute on angularjs directive - angularjs

I think it should be easy to use the well known angular attributes on a directive out of the box.
For example if the name of my directive is myDirective I would like to use it this way:
<div ng-controller="myController">
<my-directive ng-click="doSomething()"><my-directive>
</div>
instead of needing to define a custom click attribute (onClick) as in the example below
<div ng-controller="myController">
<my-directive on-click="doSomething()"><my-directive>
</div>
It seems that ng-click can work, but then you need to specify ng-controller on the directive tag too which I don't want. I want to define the controller on a surrounding div
Is it possible to use ng-click on a directive together with a controller defined on a parent html element?

Here is updated code. Maybe is this what you were looking for.
Html:
<div data-ng-app="myApp">
<div data-ng-controller="MyController">
<my-directive data-ng-click="myFirstFunction('Hallo')"></my-directive>
<my-directive data-ng-click="mySecondFunction('Hi')"></my-directive>
</div>
</div>
Angular:
var app = angular.module('myApp', []);
app.directive('myDirective', function(){
return {
restrict: 'EA',
replace: true,
scope: {
eventHandler: '&ngClick'
},
template: '<div id="holder"><button data-ng-click="eventHandler()">Call own function</button></div>'
};
});
app.controller('MyController', ['$scope', function($scope) {
$scope.myFirstFunction = function(msg) {
alert(msg + '!!! first function call!');
};
$scope.mySecondFunction = function(msg) {
alert(msg + '!!! second function call!');
};
}]);
Edit
Check solution that I made in jsFiddler is that what you were looking for?
http://jsfiddle.net/migontech/3QRDt/1/

Related

Creating directive AngularJS without $scope

I´m learning AngularJS. Now I´m trying the directives. I created a directive but I can´t make it work. I can do it with $scope, but I want to know HOW to do it without it.
The code:
<div ng-app="myApp" ng-controller="controls">
<div the-name></div>
</div>
<script src="angular.js"></script>
<script>
var modu = angular.module("myApp", []);
modu.controller("controls", [function() {
var self = this;
self.user = {
name : "Pedro",
lastname: "Delgado"
};
}]);
modu.directive("theName", [function() {
return {
template: 'Name: {{user.name}}'
};
}]);
</script>
An the RESULT is:
Name:
And I want:
Name: Pedro
Anyone can help me?
Thanks a lot!
It's called controller-as syntax. You need to create an alias to controller in the template:
<div ng-app="myApp" ng-controller="controls as ctrl">
<div the-name></div>
</div>
and then in directive template use {{ctrl.user.name}}.
But ideally, you isolate the scope of the directive, because you don't want it to know about its surroundings and what controllerAs alias is used.
This version of your directive will be much more reusable:
modu.directive("theName", [function() {
return {
scope: {
user: '='
},
template: 'Name: {{user.name}}'
};
}]);
and usage is:
<div ng-app="myApp" ng-controller="controls as ctrl">
<div the-name user="ctrl.user"></div>
</div>
So in this case, directive (and template) doesn't know anything about environment it's used (about controller prefix, etc), it only cares that proper user object was passed in it. This is the point of isolated scope.

Angularjs directive, call same directive from within itself

I am building generic angularjs directive to support editing of json object. I have json data and also admin data to have details about original data. Following code details which I am using to build my generic directive.
Please refer Plunker for running code.
http://plnkr.co/edit/x2lqHjYq48gwxW7oYyEQ?p=preview
Directive Code:
app.directive("objecteditor", [function () {
return {
restrict: "E",
templateUrl: "ObjectEditor.html",
replace: true,
scope: {
object: '=',
objectAdmin: '='
},
link: function (scope, element, attrs) {
//Method to initialize
scope.init = function () {
};
//Call init() to initialze the loading.
scope.init();
}
};
}]);
Directive Template:
<div>
<h4 data-ng-bind-template="{{objectAdmin.displayName}}"></h4>
<div data-ng-repeat="column in objectAdmin.objectDefinition">
<div data-ng-switch="column.type">
<div data-ng-switch-when="string">
<label class="label-plain" data-ng-bind-template="{{column.displayName}}"></label>
<input type="text" data-ng-model="object[objectAdmin.name][column.name]" placeholder="{{displayName}}" title="{{displayName}}" name="textBox{{name}}" required />
</div>
<!--Call same object for child type as object. But how??? If i call <object> directive here then goes into infinite cycle -->
<div data-ng-switch-when="object">
</div>
</div>
</div>
</div>
Controller Code:
var app = angular.module("myApp", []);
app.controller('ApplicationController', ['$scope',
function($scope) {
//Method to initialize
$scope.init = function() {
//Set json data strucutre for editing
$scope.objectAdmin ={"name":"bankinfo","displayName":"Bank Info","type":"object","objectDefinition":[{"name":"name","displayName":"Bank Name","type":"string"},{"name":"mainPhone","displayName":"Main Phone","type":"string"},{"name":"contact","displayName":"Contact","type":"object","objectDefinition":[{"name":"name","displayName":"Name","type":"string"},{"name":"title","displayName":"Title","type":"string"}]}]};
$scope.object={"bankinfo":{"name":"Chase Bank - Newburgh","mainPhone":"1 (845) 333-3333","contact":{"name":"Donna Shuler","title":"Commercial Accounts Mgr."}}};
};
//Call init() to initialze the loading.
$scope.init();
}
]);
Index.html
<!doctype html>
<html ng-app='myApp'>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script src="script.js"></script>
<script src="ObjectEditor.js"></script>
</head>
<body data-ng-controller="ApplicationController">
<h2>How to call same directive within itself?</h2>
<!--Use object editor directive to edit the object details -->
<objecteditor data-object="object" data-object-admin="objectAdmin"></objecteditor>
</body>
</html>
I want to make my directive generic so that same type of object editing can be supported by single directive.
When I tried to call same directive within itself then it fall into infinite loop (which is expected).
How can I achieve this functionality in directive?
Please help.
I was going through the recursive directive and came across following post which was helpful to implement my requirement.
https://www.packtpub.com/books/content/recursive-directives. Following is code to implement this.
Object Editor Directive Template:
<div>
<objecttree data-object="object" data-object-admin="objectAdmin" data-folder-guid="folderGuid" data-hide-header="'true'"></objecttree>
<script type="text/ng-template" id="objectTree">
<div class="clear-left">
<h4 data-ng-if="!hideHeader" data-ng-bind-template="{{objectAdmin.displayName}}"></h4>
<div data-ng-repeat="column in objectAdmin.objectDefinition">
<div data-ng-switch="column.type">
<imageeditor data-ng-switch-when="image" data-image="object[column.name]" data-folder-guid="folderGuid" data-column="column"></imageeditor>
<formcheckbox data-ng-switch-when="boolean" data-input-value="object[column.name]" data-editable="column.editable" data-name="column.name" data-display-name="column.displayName" data-formName="'resourceAddEditFormName'"></formcheckbox>
<addresseditor data-ng-switch-when="address" data-address="object[column.name]" data-column="column" data-collection-admin="objectAdmin"></addresseditor>
<formtextbox data-ng-switch-when="string" data-ng-if="!column.isDropdown" data-input-value="object[column.name]" data-editable="column.editable" data-name="column.name" data-display-name="column.displayName" data-formName="'resourceAddEditFormName'"></formtextbox>
<dropdownbox data-ng-switch-when="string" data-ng-if="column.isDropdown" class="admin-textbox" data-selected-id-list="object[column.name]" data-dropdown="column" data-multiple="column.dropdownTypeMultiple"></dropdownbox>
<div data-ng-switch-when="object">
<hr/>
<objecttree data-object="object[column.name]" data-object-admin="column" data-folder-guid="folderGuid" data-hide-header="'true'"></objecttree>
</div>
<div data-ng-switch-when="array">
<hr/>
<arrayobjecttree data-objects="object[column.name]" data-objects-admin="column" data-folder-guid="folderGuid" data-hide-header="'true'"></arrayobjecttree>
</div>
</div>
</div>
</div>
</script>
</div>
Object Tree:
app.directive("objecttree", ['$compile', '$templateCache', function ($compile, $templateCache) {
return {
restrict: "E",
scope: {
object: '=',
objectAdmin: '=',
folderGuid: '=',
hideHeader: '='
},
link: function (scope, element, attrs) {
element.replaceWith(
$compile(
$templateCache.get('objectTree')
)(scope)
);
}
};
}]);
This is Shankar. You can use the below solution for recursive directive.
Please confirm me whether this resolves your issue.If not, you can let me know.
As I'm not able to paste my entire code here, you can find the solution in my Github repository:(i.e. gmssankar/myRepository/Recursive Directive)
https://github.com/gmssankar/myRepository/blob/master/Recursive%20Directive
The code can be found in the following link too in plunker:
plnkr.co/edit/WrZekRS5AzfFJhQ2d3XK?p=preview
I'm not able to attach the complete code here as it restricts the number of lines. The logic is: Inside Directive template display bank name, main phone,contact name and contact title from the passed object. Then check if the passed object, has object definition (i.e child nodes). If yes, then extract each child using ng-repeat , and pass to same directive. Issue gets resolved here. From Github or plnkr , you can access the complete code.

Angular directive referencing wrong element

I have an issue where a directive i'm using for several similar elements in an ng repeat is showing the wrong element when calling the keyup function.
plunker: http://plnkr.co/edit/ARFlsgPdxikpzLScztxU?p=preview
Here's the same code:
html
<body ng-app="app">
<section ng-controller="MainController" ng-repeat="item in list">
<div ng-repeat="item in list">
<h3>Item {{$index}}</h3>
<div class="aliasContainer">
<input text="text" obj-key="alias" value="{{item.alias}}" ng-keyup="logItem($event, item)">
</div>
<div class="nameContainer">
<input text="text" obj-key="name" value="{{item.name}}" ng-keyup="logItem($event, item)">
</div>
</div>
</section>
<script src="https://code.angularjs.org/1.2.25/angular.js"></script>
<script src="script.js"></script>
</body>
js
var app = angular.module('app', []);
app.controller('MainController', ['$scope', function($scope){
console.log("hello ctrl");
$scope.list = [
{name: 'Dick Grayson', alias: 'Nightwing'},
{name: 'Bruce Wayne', alias: 'Batman'},
{name: 'Jason Todd', alias: 'Robin'}
];
}]);
app.directive('objKey', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
scope.logItem = function($event, item) {
console.log(element);
};
}
};
});
The behavior the link function is exhibiting is for each div that is repeated, only the the input in the nameContainer gets passed on keyup (logging the element will show the input in nameContainer of the same parent div even if the input in aliasContainer was the triggering element.)
To reuse your directive and keeping its scope separate from outer scope (controller), you need to have a isolate scope to your directive
app.directive('objKey', function() {
return {
restrict: 'A',
scope: true, // << Isolating scope
link: ....
}
};
You should look into directive's scope: https://docs.angularjs.org/guide/directive
If you don't isolate the scope, your directive's scope will be the same as the scope when it's declared, in this case it will use the child scope created by ng-repeat.
To fix this, just isolate the scope with scope: true

Transclude inside ng-repeat, controller function incorrect transclude param

I created directive that appends transclude value after the directive body. I cant use ng-transclude inside my directive because it creates for the simple text as transclude value and it break my page. I use
controller: function($scope, $element, $transclude) {
$element.append($transclude().contents());
}
to append it. It works great, but when I use my directive inside ng-repeat something goes wrong and $transclude().contents() don't contain my text. Can someone explain this behavior?
Here example:
http://plnkr.co/edit/1y4avkwmgjhiKkuoZlug
I can't explain why $transclude().contents() don't contain your text, but I can show how to easy fix that please code below.
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
});
app.directive('test', function(){
return {
transclude: true,
restrict: 'E',
template: '<div >From directive </div> <div ng-transclude></div><hr/>',
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<body ng-app="app">
<div ng-controller="MainCtrl">
<div ng-repeat="a in [1, 2, 3, 4, 5]">
<test>From transclude {{a}}</test>
</div>
</body>

Using ng-switch in directive with transclude

I am trying to create a template that shows some transcluded content. When I use ng-show everything works fine, but using ng-if or ng-switch gives me problems. I get this error message: Illegal use of ngTransclude directive in the template! No parent directive that requires a transclusion found
I understand that ng-switch creates a new scope. But the transclude should still go up to the parent chain. Is this a defect in angularjs? See http://jsfiddle.net/HgvP7/
Here is my html, modified from the documentation example:
<div ng-app="docsTransclusionExample">
<div ng-controller="Ctrl">
<my-dialog>Check out the contents, {{name}}!</my-dialog>
</div>
<!-- my-dialog.html -->
<script type="text/ng-template" id="my-dialog.html">
<div ng-switch="1+1">
<div ng-switch-when="2">
<div ng-transclude></div>
</div>
</div>
</script>
</div>
And the code:
angular.module('docsTransclusionExample', [])
.controller('Ctrl', function($scope) {
$scope.name = 'Tobias';
})
.directive('myDialog', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
templateUrl: 'my-dialog.html',
link: function (scope, element) {
scope.name = 'Jeff';
}
};
});

Resources