I am trying to understand the execution of link function in angular directives. However, I am stuck in a very simple setup. Following is the html code:
<!doctype html>
<html ng-app="demoApp">
<body>
<div ng-controller="DemoController" class="container">
<directiveone directivetwo ></directiveone>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<script src="app.js"></script>
</body>
</html>
"demoApp" is defined in app.js as follows:
angular.module('demoApp', [])
.controller("DemoController", function(){
})
.directive("directiveone", function(){
var linker = function(scope, element, attrs){
console.log("directiveone link called");
};
return {
link : linker
}
})
.directive("directivetwo", function(){
var linker = function(scope, element, attrs){
console.log("directivetwo link called");
};
return {
require: "directiveone",
link : linker
};
});
When I run this code, I get the error:
Controller 'directiveone', required by directive 'directivetwo', can't be found!
I am unable to figure out the error here. Documentation suggests it might be a typo, but it is not apparent to me.
Directives default to attribute-only. Your directiveone directive isn't being picked up - you need to specify restrict: 'E' in its definition, or apply it as an attribute (<div directiveone directivetwo>...)
Related
<body ng-controller="MyController">
<mydirective></mydirective>
</body>
Is there any way in AngularJS to attach dynamic event without using directive tag because it may need to add additional tag in html.
<!DOCTYPE html>
<html ng-app="appname">
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.min.js"></script>
</head>
<body ng-controller="MyController">
<mydirective></mydirective>
</body>
<script>
var app = angular.module('appname', []);
app.controller('MyController', function($scope){
});
app.directive('mydirective', function(){
return {
restrict: 'E',
link: function(scope, elem, attrs){
angular.element(document).bind('mousedown', function(){
console.log('clicked on document');
});
}
}
});
</script>
</html>
Sure you can. Take a look at the following JSFiddle.
However, always and always remember to unbind events as well, otherwise it might lead to memory leaks and other unwanted scenarios.
var buttonElement = angular.element('#myButton');
buttonElement.bind('click', function (e) {
alert('This is a code bound event');
});
Also, using directives such as 'ng-click', ng-mouseover' is always advised, since these are well-developed and well-tested by thousands and thousands of developers. It will help you to develop robust applications
JSFiddle: Bind events through code << Updated the fiddle based on OP's comments
I want to use multiple instances of the same directive to render a collection. I am using an isolate scope to map an array to a name in the isolate scope. The link function in the isolate scope correctly sees the mapped array, however ng-repeat in it does not work.
<html ng-app="MyApp">
<head>
<script type="text/javascript" src="angular.js"></script>
<script type="text/javascript">
var MyCtrl = function($scope) {
$scope.blah = [1,2,4,5];
$scope.bar = [14,52,64,25];
}
angular.module("MyApp", [])
.directive("sephBlah", function($parse) {
return {
scope: {
tags: "=sephBlah"
},
link: function(scope, elem, attrs) {
console.log(scope.tags[0]);
}
}
});
</script>
</head>
<body ng-controller="MyCtrl">
<div seph-blah="blah">
<p data-ng-repeat="t in tags">{{t}}</p><!-- why this renders nothing? -->
</div>
<div seph-blah="bar">
<p data-ng-repeat="t in tags">{{t}}</p><!-- why this renders nothing? -->
</div>
</body>
</html>
I am not sure why the ng-repeat renders nothing. The link function correctly sees the arrays.
You're not supposed to use directives like this. The sort of functionality you're trying to get here should be done with a controller.
When using directives, use the template or templateUrl attribute to provide content. So this will work:
.directive("sephBlah", function($parse) {
return {
scope: {
tags: "=sephBlah"
},
template: '<p data-ng-repeat="t in tags">{{t}}</p>',
link: function(scope, elem, attrs) {
console.log(scope.tags[0]);
}
}
});
And in the html just do:
<div ng-attr-seph-blah="blah"></div>
I'm pretty sure I'm doing this the wrong way, so any help would be appreciated...
Given the following plunker: http://plnkr.co/edit/hCjTdt8XmlVPKGgzvgFu?p=preview
I'm trying to compile some Html and insert it in a specific location in my template. However, I'm getting an error:
Can't interpolate: My Value: {{innerHtml}}
TypeError: Converting circular structure to JSON
I'm pretty sure this is because I'm attempting to insert the entire element as Html, but I'm not sure how to accomplish what I'm trying to do.
Plunker code:
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body ng-app='myApp'>
<div ng-controller='TestCtrl'>
<test-directive></test-directive>
</div>
<script>
var app = angular.module('myApp', []);
app.controller("TestCtrl", ['$scope', function($scope) {
$scope.myValue = "Hello, World!";
}]);
app.directive('testDirective', ['$compile', function($compile) {
return {
restrict: 'E',
template: "<h1>Title</h1>My Value: {{innerHtml}}",
link: function (scope, element, attr) {
scope.innerHtml = $compile("<input type='text' ng-model='myValue' />")(scope);
}
}
}]);
</script>
</body>
</html>
I think you may be confused by trying to access innerHtml on your scope? I think you need to be accessing your element to insert DOM. The element will be basically whatever's in your template, but already compiled (link happens after compile). So you can compile and add it to your element.
Try this:
element.append($compile("<input type='text' ng-model='myValue' />")(scope));
instead of scope.innerHtml line. Working in plnkr: http://plnkr.co/edit/z3k6BPVNcNxi6d4XBfXX?p=preview
I am new to AngularJs. I have created a simple custom directive in Angular to print out some text. The code is below:
var demoApp = angular.module('demo-app', ['ngRoute']);
demoApp.directive('helloWorld', function() {
return {
restrict: 'E',
template: '<h1>Hello World!!</h1>'
};
});
In the html file I am using it like below:
<hello-world/>
<script type="text/javascript" src="js/demo-app.js"></script>
I am not seeing the output "Hello World!". Please let me know where I am going wrong? I am using Angular 1.3 version.
I did it following way in my project, and it is working fine.
customDirective.js
myApp.directive('viewTodoSuccessModal', function () {
return {
restrict: 'E',
templateUrl: '/scripts/app-angular/directives/templates/view-todo-success-modal.html'
};
});
app.js
angular.module('myApp', [
'myAppControllers'
, 'myAppDirectives'
]);
included/referenced in html page
<script src="#Url.Content("~/Scripts/app-angular/app.js")"></script>
<script src="#Url.Content("~/Scripts/app-angular/Directives/CustomDirectives.js")"></script>
Hope it helps
Just check whether your module name is 'demo-app' in html or not.If it is not then make it correct.module name in script file should be same as html file.
<html ng-app="demo-app">
<head>
<script src="angular.js"></script>
</head>
<body>
<hello-world />
<script type="text/javascript">
angular.module('demo-app',[]);
angular.module('demo-app')
.directive('helloWorld', function() {
return {
restrict: 'E',
template: '<h1>Hello World!!</h1>'
};
});
</script>
</body>
</html>
JS Fiddle: http://jsfiddle.net/vSpR4/1/
Consider the following code (http://jsbin.com/IfejIWES/1/):
HTML:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.3/angular.min.js"></script>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
<div ng-controller="MyCtrl">
<div my-directive>
<button>some button</button>
and a link
</div>
</div>
</body>
</html>
JS:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
//$scope.log=[];
}
myApp.directive('myDirective', function(){
return{
transclude: true,
template: '<div class="something" ng-transclude> This is my directive content</div>'
};
});
Using version 1.1.3 of AngularJS, the output combines the button and anchor from my-directive (in the HTML) with the template inner text 'This is my directive content'.
If I change the version to 1.2.1 the my-directive content replaces the template inner text.
Is there a way to have angular 1.2.1 (and later) do the older behavior?
No. This was a very intentional change. See this commit.
The link provided by Jeff Hubbard (thanks Jeff) started me in the right direction. From the comments of that post somebody (https://github.com/angular/angular.js/commit/eed299a31b5a6dd0363133c5f9271bf33d090c94#commitcomment-4685184) posted a work around: http://plnkr.co/edit/EjO8SpUT91PuXP0RMuJx?p=preview
Essentially, you can get the old behavior back by changing the JavaScript to use the transcludeFn function in a separate directive. See below my updated code:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
}
myApp.directive('myDirective', function(){
return{
transclude: true,
template: '<div class="something" ng-transclude-append> This is my directive content</div>'
};
});
myApp.directive('ngTranscludeAppend', function() {
return function(scope, element, attrs, ctrl, transcludeFn) {
if (!transcludeFn) return;
transcludeFn(function(clone) {
element.append(clone);
});
};
});
Link to my updated jsbin: http://jsbin.com/IfejIWES/3/
One last note, I tried embedding the transcludeFn in my link function directly like:
link: function(scope, element, attrs, ctrl, transcludeFn) {
transcludeFn(function(clone) {
element.append(clone);
});
}
But this had the effect of creating the button and anchor twice. Moving it out into its own directive solved it for me.