AngularJs dynamic Event handler without using directive - angularjs

<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

Related

AngularJS - How do I know immediately when an input has been changed if it is debounced?

Having a text input I want to know immediately when the user is changing the text, but also I want to use the debounce feature. This way I can, for example, disable a submit button while the user is changing the text and enable the submit button after checking the text in the debounced function.
Is there a way to do this with pure AngularJS? Or should I use javascript/jquery?
With this code I am only able to know when the user has changed the text after the debounce 500ms delay:
<!doctype html>
<html ng-app="app">
<head>
<script src="http://localhost/js/angular.min.js"></script>
<script>
var app= angular.module('app',[]);
app.controller('ExampleController',['$scope',function($scope){
$scope.changed= '';
$scope.change= function(){
$scope.changed= 'Changed!';
};
}]);
</script>
</head>
<body ng-controller="ExampleController">
<div>Message: <input type="text" ng-model="model.message"
ng-model-options="{debounce:500}" ng-change="change()" />
<div>{{model.message}}</div>
<div>{{changed}}</div>
</body>
</html>
Your main option is to write your own debouncing code using ng-keyup. Every time a key is pressed, you will be notified of the change (and the change will be present in the ng-model value) and you can use your own setTimeout there, with the desired debounce function as the callback. If the timeout is already set, simply cancel it and restart it on each key press.
Use $scope.$watch('model-name', function(){...}
angular.module('customControl').
directive('contenteditable', [function() {
return {
restrict: 'A', // only activate on element attribute
require: '?ngModel', // get a hold of NgModelController
link: function(scope, element, attrs, ngModel) {
if (!ngModel) return; // do nothing if no ng-model
ngModel.$parsers.push(function(value) {
// do what you want to happen before "debounce"
// debounce here by waiting 500ms
});
}
};
}]);
source: https://code.angularjs.org/1.4.1/docs/api/ng/type/ngModel.NgModelController
Not being able to do this in a simple way I've finished doing it outside of angular with underscore library. That is the best option that I have found.
Here is my code:
<!doctype html>
<html ng-app="app">
<head>
<script src="http://localhost/js/angular.min.js"></script>
<script src="http://localhost/js/underscore.js"></script>
<script>
var underscore= angular.module('underscore',[]);
underscore.factory('_',function(){
return window._; // assumes underscore has already been loaded on the page
});
var app= angular.module('app',['underscore']);
app.controller('ExampleController',['$scope','_',function($scope,_){
$scope.changed= '';
$scope.change= function(){
$scope.debounceMessage($scope);
};
$scope.debounceMessage= _.debounce(function($scope){
$scope.$apply(function(){
$scope.changed= 'Delayed: '+$scope.model.message;
});
}, 500);
}]);
</script>
</head>
<body ng-controller="ExampleController">
<div>Message: <input type="text" ng-model="model.message"
ng-change="change()" />
<div>{{model.message}}</div>
<div>{{changed}}</div>
</body>
</html>
http://plnkr.co/edit/0gnwg9

Required angular directive not found

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>...)

AngularJS - How do I insert compiled HTML into my directive template?

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

Transclusion (true) - Combining values

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.

Talking to Angular Directive from Controller

I have a directive and I want to call a method of the Directive from outside controller . That means when I click a button in the main controller , I want to hide a component in the directive . Is this really possible ,If yes please help me .
Kamal
To call directive methods outside in a controller I would share a directive control object with the controller. Inside the controller you can call methods of this control object and they get executed inside your directive.
create a control object inside your directive
share this control object with the controller using tw data binding
call methods on this control object inside your controller
here is a plunker that demonstrates it: http://plnkr.co/edit/MqN9yS8R5dnqTfjqldwX?p=preview
You can accomplish this by allowing your directive to listen to a scoped property from your controller. Using isolated scope and the =, you can tell your directive what to pay attention to in order to hide its component:
Html:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script data-require="angular.js#*" data-semver="1.2.0-rc3-nonmin" src="http://code.angularjs.org/1.2.0-rc.3/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="Ctrl">
<h1>Hello Plunker!</h1>
<button ng-click="action()">Toggle</button>
<the-directive show-component="showIt"></the-directive>
</body>
</html>
JavaScript:
var myApp = angular.module('myApp', []);
myApp.controller('Ctrl', function($scope) {
$scope.showIt = true;
$scope.action = function() {
$scope.showIt = !$scope.showIt;
}
});
myApp.directive('theDirective', function() {
return {
restrict: 'E',
scope: {
'showComponent': '='
},
template: '<div><div ng-show="showComponent">show Me!</div></div>'
}
})
Here is a plunker demonstrating the technique.

Resources