Angular Custom Directive Does not trigger ng-click - angularjs

I have a directive which populates content using ng-repeat. I have an ng-click / ng-focus event on each element inside but the click does not trigger the action.
This works when I remov the ng-repeat from the template. I'm using angularjs 1.3.4
app.directive('inputTable', [function(){
restrict: 'E',
template: '<div ng-repeat="item in items" >
<div >
<input type="text" ng-focus="focusTap()" ng-model="item.name" placeholder="Name">
</div>
</div>',
replace:true,
scope: {
items:'=items'
},
controller:['$scope', '$element', function($scope, $element ){
$scope.focusTap = function(){
console.log('focus called');
}
}],
link: ['$scope', '$element', 'attributes', function($scope, $element, attributes){
}],
}]

Seems to be a bug. Works as expected in 1.3.0-beta.10, but not later versions.
If using a newer version then remove replace: true and it will work.
Demo: http://plnkr.co/edit/hb5eWfoYH4PCkNaYaxn6?p=preview

Related

AngularJS custom form component / directive using ng-model

Angular custom form component / directive and $dirty property
When using regular input, such as
<form name="myForm">
<input type="text" ng-model="foobar">
</form>
after typing in the input box myForm.$dirty is true.
I'd like to create a simple directive such as
angular.module('myModule', [])
.directive('myDirective', function() {
return {
restrict: 'E',
scope: {
fooBar: '='
},
template: '<div><button ng-click="fooBar=foo"></button><button ng-click="fooBar=bar"></button></div>'
};
});
Sample usage would be
<form name="myForm">
<my-directive foo-bar="myObj.foobarValue"></my-directive>
</form>
and after user clicks on any of the two buttons, myForm$dirty is set to true.
How is this accomplished?
Implementing custom form controls (using ngModel)
Use the ngModel controller and the object form of the require property in the DDO:
angular.module('myModule', [])
.directive('myDirective', function() {
return {
restrict: 'E',
require: { ngModelCtrl: 'ngModel' },
scope: {
ngModel: '<'
},
bindToController: true,
controllerAs: '$ctrl',
template:
`<div>
<button ng-click="$ctrl.ngModelCtrl.$setViewValue('foo')">
Set foo
</button>
<button ng-click="$ctrl.ngModelCtrl.$setViewValue('bar')">
Set bar
</button>
</div>`,
controller: function ctrl() {}
};
});
Usage:
<form name="myForm">
<input type="text" ng-model="foobar">
<my-directive ng-model="foobar"></my-directive>
</form>
By instantiating and using the ng-model controller, the directive will automatically set the form controls as necessary.
The DEMO
angular.module('myModule', [])
.directive('myDirective', function() {
return {
restrict: 'E',
require: { ngModelCtrl: 'ngModel' },
scope: {
ngModel: '<'
},
bindToController: true,
controllerAs: '$ctrl',
template:
`<div>
<button ng-click="$ctrl.ngModelCtrl.$setViewValue('foo')">
Set foo
</button>
<button ng-click="$ctrl.ngModelCtrl.$setViewValue('bar')">
Set bar
</button>
</div>`,
controller: function ctrl() {}
};
});
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="myModule">
<h2>ngModel DEMO</h2>
<form name="myForm">
<input type="text" ng-model="foobar">
<my-directive ng-model="foobar"></my-directive>
</form>
<br>myForm.$dirty = {{myForm.$dirty}}
<br>myForm.$pristine = {{myForm.$pristine}}
<br><button ng-click="myForm.$setDirty()">Set dirty</button>
<br><button ng-click="myForm.$setPristine()">Set pristine</button>
</body>
I recommend isolate scope with ngModel as an input. Output should be done with the $setViewValue method.
For more information, see
AngularJS Developer Guide - Implementing custom form controls (using ngModel)
AngularJS Developer Guide - Component-based application architecture

angular bind html tags from controller to html view

I need to render the $scope.htmlView tags in to html view.
I already tried using ng-bind-html. It renders the html tags but scope variable values will not appear.
How can I render both html tags and and scope variable values?
This is the controller:
$scope.newObj = {
billStatus : true;
eventTime : "2015-01-10"
};
$scope.htmlView = '<p>{{newObj.eventTime}}</p> <div style="margin-top: -15px;"><md-checkbox ng-checked="{{newObj.billStatus}}" style="margin-left: 0px;" aria-label="Bilable"><span style="margin-left:0px;">Bilable</span> </md-checkbox></div>'
Expected result is:
<p> 2015-01-10</p>
<div style="margin-top: -15px;">
<md-checkbox ng-checked="true" style="margin-left: 0px;" aria- label="Bilable">
<span style="margin-left:0px;">Bilable</span>
</md-checkbox>
</div>
I search over the internet over days and still could't find out a way to figure out this. please help me. thank you.
You have to do 2 things.
Use data-ng-bind-html=""
Use $sce.trustAsHtml(string)
UPDATED:
If you wont to use angular expressions, you have to compile them using
$compile.
You can read more via this $SCE
I will tell you a long way but it will help you.Make a custom directive like this.
app.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, ele, attrs) {
scope.$watch(attrs.dynamic, function(html) {
ele.html(html);
$compile(ele.contents())(scope);
});
}
};
});
Use as
<span dynamic="{{htmlView}}" >
Hi please check this fiddle
https://plnkr.co/edit/iqNltdDYv2n9Agke0C2C?p=preview
HTML
<div ng-controller="ExampleController">
<p >{{newObj.eventTime}}</p>
<p dynamic="htmlView"></p>
</div
and JS
(function(angular) {
'use strict';
angular.module('bindHtmlExample', ['ngSanitize'])
.controller('ExampleController', ['$scope', function($scope) {
$scope.newObj = {
billStatus : true,
eventTime : "2015-01-10"
}
$scope.htmlView = '<p> {{newObj.eventTime}}</p> <div style="margin-top: -15px;">Hello <md-checkbox ng-checked="{{newObj.billStatus}}" style="margin-left: 0px;" aria-label="Bilable"><span style="margin-left:0px;">Bilable</span> </md-checkbox></div>'
}])
.directive('dynamic', function($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, element, attrs) {
scope.$watch(attrs.dynamic, function(html) {
element[0].innerHTML = html;
$compile(element.contents())(scope);
});
}
};
});
})(window.angular);

Decorating AngularJS Directive template inside the directive

I have a directive which is defined, say, as below:
angular.module('some-module').directive('someDirective', function() {
return {
restrict: 'E',
replace: 'true',
templateUrl: 'some-template.html',
link: link,
require: '^form',
transclude: true,
scope: {
decorate: '=',
}
};
});
Let's say this is how the some-template.html looks (there is more in the actual template though):
<div ng-transclude></div>
And this is how I will use the directive:
<some-directive decorate="true">
<input name="x" type="number" ng-model="x">
<input name="y" type="number" ng-model="y">
</some-directive>
<some-directive decorate="false">
<input name="a" type="number" ng-model="a">
<input name="b" type="number" ng-model="b">
</some-directive>
What I want the directive to do is to manipulate the DOM so that if decorate is true then, the two input fields should be decorated with some divs as below:
<div class="some-outer-class">
<div class="some-class-1">
<input name="x" type="number" ng-model="x">
</div>
<div class="some-class-2">
<input name="y" type="number" ng-model="y">
</div>
<div><i class="some-glyph-icon"></i></div>
</div>
If the decorate attribute is false, or absent, the directive shouldn't do any manipulation.
Couldn't figure out how to do this. Any help is appreciated.
You can simply modify the template in link function :
Demo
link: function(scope, elem, attrs){
if(scope.decorate || attrs.decorate != null){
elem.find('INPUT').wrap('<div class="decorate-class"></div>')
}
}
You can do this inside the directive. You first define a controller inside your directive as follows:
angular.module('some-module').directive('someDirective', function() {
var controller = function($scope) {
//The controller methods
};
return {
restrict: 'E',
replace: 'true',
templateUrl: 'some-template.html',
link: link,
require: '^form',
transclude: true,
scope: {
decorate: '=',
},
controller: controller,
controllerAs: 'myCtrl'
};
});
Inside the controller, you check the decorate value, and make the DOM manipulation accordingly. You can access the decorate value from your controller via the $scope.
var controller = function($scope) {
if($scope.decorate){
//Make the DOM manipulation
}
};
DOM manipulation is done as follows:
var initialInput = document.querySelector('query'); //You have to select your desired input elements here
var decoratedInput = document.createElement("div");
decoratedInput.className += " some-class-1";
decoratedInput.innerHTML = "<input name='x' type='number' ng-model='x'>";
initialInput.parentNode.replaceChild(decoratedInput, initialInput);

Reusing a directive template for multiple forms with isolated scope

I'm working on a project where the user needs to be able to create many instances of the same form. As of now the user can click a button to create one or more forms. The problem I'm having is that by isolating the scope, as I think I should be doing given that I'm reusing the same directive, my ng-models can't communicate with the parent controller.
My directive for <rule-form></rule-form>..
(function(){
'use strict';
var ruleForm = function(){
return{
restrict: 'E',
replace: true,
scope: {},
templateUrl: 'edit/rule-create/ruleForm.html',
link: function(scope, element, attrs){
scope.length = document.forms.length;
}
}
}
angular.module('ganeshaApp')
.directive('ruleForm', ruleForm)
})();
And my template...
<form class="edit__div--rule-form" name="form_{{length}}">
<input type="text" placeholder="Rule Title" ng-model="rcCtrl.ruleTitle">
<div class="edit__div--rc-toolbar">
<select class="edit__btn--rc-select" ng-model="rcCtrl.select" apply-statement-type>
<option value="obligation statement">obligation statement</option>
<option value="prohibition statement">prohibition statement</option>
<option value="permission statement">restricted permission statement</option>
</select>
<div class="edit__btn--rc-noun">
Add noun/verb
</div>
<div class="edit__btn--rc-save" ng-click="rcCtrl.saveRule()">
<span class="glyphicon glyphicon-floppy-saved"></span>Save
</div>
<div class="edit__btn--rc-cancel">
<span class="glyphicon glyphicon-remove"></span>
Cancel
</div>
</div>
<div class="edit__select--statement-type"></div>
<div ng-show="rcCtrl.showTextEdit" class="edit__div--rule-form-text" contenteditable="true" ng-model="rcCtrl.ruleText"></div>
I tried using $parent , (e.g. $parent.rcCtrl.ruleText), but then I'm back to the problem of not having isolated scopes and each form updates the others. I'm a bit confused about this really. Does anyone know a solution to this problem, or is it just a problem with my code?
Add a controller to your directive.
angular.module('ganeshaApp').directive('ruleForm', function(){
return {
restrict: 'E',
replace: true,
scope: {},
templateUrl: 'edit/rule-create/ruleForm.html',
controller: "rulesFormController as rcCtrl",
link: function(scope, element, attrs){
scope.length = document.forms.length;
}
}
});
The AngularJS $compile service will then create an instance of the controller for each instance of the directive and attach it to each isolate scope.
For more information, see the AngularJS Comprehensive Directive API Reference.

Bootstrap switch not working for nested directives inside ng-repeat

Please read the code below:
<div ng-repeat="item in data.items">
<list-item></list-item>
</div>
Html(list_item.html) of the above directive(listItem) is as below(have shown only a small part of html):
<div class="active-icon-list">
<switch-check status="{{ item.status }}"></switch-check>
</div>
js of the above directive is as below:
directives.directive('cusListItem', function(){
return {
replace: true,
restrict: 'E',
templateUrl: "list_item.html",
link: function($scope, iElm, iAttrs, controller) {
// -----
}
};
});
Html(switch_check.html) of the above directive(switchCheck) is as below:
<div class="make-switch switch-small switch-mini active-list-switch">
<input type="checkbox" checked ng-if="status == 'active'">
<input type="checkbox" ng-if="status == 'inactive'">
</div>
js of the above directive is as below:
directives.directive('switchCheck', function($timeout) {
var switches = [];
return {
replace: true,
restrict: 'E',
scope: { status: '#'},
templateUrl: "switch_check.html",
link: function postLink($scope, iElm, iAttrs) {
iElm['bootstrapSwitch']();
}
}
});
I have made directives for the purpose of reusability.
Since I am using bootstrapSwitch.js instead of normal checkbox, I have created a directive.
If a remove ng-if and write a traditional input tag, this works properly.
<input type="checkbox" checked>
But if I use ng-if, iElm['bootstrapSwitch'](); fails and checkbox does not appear at all.
Is there a way(an efficient one) to figure out a solution for this one?
Please tell me if my question is not clear.

Resources