How to make ng-click from injected html to work? - angularjs

I'm using datatables along with angular and I have this piece of code:
render: function (data, type, full, meta) {
var buttonHtml = '<div style="text-align: center;">' +
'<button data-toggle="modal" data-target="#myModal" class="btn btn-primary btn-xs" data-ng-click="loadModal(' + meta.row + ')">' +
'<i class="fa fa-folder-open-o"></i> View' +
'</button>' +
'</div>';
return buttonHtml;
}
The above it's a handler from datatables to dynamically format a column based on data.
The problem is that the ng-click handler (loadModal) is never called and I guess because the html is never compiled. How could I solve this issue?

Have a look at this answer: Angular: ng-bind-html filters out ng-click? it includes an example of a compile directive.

Related

AngularJS directive to add content after element and trigger element click

I'm trying to create a very simple directive to ask confirmation on a button click.
The following html:
<button kr-confirm>Delete</button>
Should compile into:
<button kr-confirm>Delete</button>
<span ng-show="vm.isOpen">
Are you sure?
<span class="btn btn-sm btn-danger">Yes</span>
<span class="btn btn-sm btn-secondary">No</span>
</span>
I wanted to handle this in templateUrl, but could not find an option to add template after element.
I ended up adding DOM in link function and calling element.on('click') but this doesn't seem to work.
Based on HTML and anticipated result, how would I go about implementing this?
Best case would be if it could be solved with templateUrl.
See my current fiddle:
https://jsfiddle.net/kraaness/4rn8ycb3/
You should create a component that will provide you with the desired functionality. See a quick <confirmation-button> component below.
angular.module('app', [])
.component('confirmationButton', {
bindings: {
onConfirm: '&'
},
template: '<button ng-click="$ctrl.confirm = true">Delete</button>' +
'<div ng-show="$ctrl.confirm">Are you sure?' +
'<button ng-click="$ctrl.onConfirm(); $ctrl.confirm = false">Yes</button>' +
'<button ng-click="$ctrl.confirm = false">No</button></div>'
})
.run(function($rootScope) { // using $rootScope just for sake of the demo
$rootScope.delete = function() {
alert("Oh no!");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<div ng-app="app">
<confirmation-button on-confirm="delete()"></confirmation-button>
</div>

data-ng-click event binding to the DOM

I am new to angularjs, I have code in which on clicking the 'button' one new row gets inserted with one 'new button', now in turn that 'new button' also should have ng-click event. The problem is when I try doing this, the the dynamic row with new button gets added but the new button is not getting the click event attached to it. After some research I found that I should compile the element string before adding to the DOM with the help of "$compile" service of the angularjs. but then the browser throwing error saying that '$compiler is not a function'... Please help. Thank you..!!
following are the code snippets
jsp page code
<td>
<button type="button" id="clickButton" data-ng-click="insert()"
class="btn btn-sm btn-default">
<i class="fa fa-plus fa-lg"></i>
</button>
</td>
angularjs controller code
$scope.insert = function($compile){
var tableRow ="<tr data-ng-repeat='c in ctrl.client.clientOwnerVOList' id='insertionRow"+count+"'>"+
"<td>"+i+"</td>"+
"<td class='col-lg-3'><input type='Text' class='form-control' data-ng-model='c.clientOwnerName' name='clientOwnerName{{$index + 1}}' id='Name'></td>"+
"<td class='col-lg-4'><input type='Email' class='form-control' data-ng-model='c.clientOwnerEmail' name='clientOwnerEmail{{$index + 1}}' id='Email'></td>"+
"<td class='col-lg-3'><input type='Text' class='form-control' data-ng-model='c.clientOwnerPhone' name='clientOwnerPhone{{$index + 1}}' id='PhoneNo'></td>"+
"<td><button type='button' data-ng-click=insert() class='btn btn-sm btn-default'><i class='fa fa-plus fa-lg'></i></button></td>"+
"<td><button type='button' class='btn btn-sm btn-default' onClick=$(this).closest('tr').remove();><i class='fa fa-trash fa-lg '></i></button></td>"+
"</tr>";
var newTableRow = $compile(tableRow)($scope);
$("#insertionRow").append(newTableRow);
i++;
};
You can create a directive that uses compile:
app.directive('dynamic', [ '$compile',
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);
});
}
};
}]);
Then in your html:
<div dynamic="tableRow"></div>
... wherever you want the table row to show.
Why are you passing $compile as the function argument?You should inject $compile service just as you inject $scope , i.e in your controller/directive.
That might be the reason , it is throwing $compile is not a function error.

How to use index of each item when item is written in directive?

I just want to point out that this is my first attempt to create simple app in AngularJS.I have a table , and in each row I'm displaying task which contains Index,Name,Activity,Time properties and also edit and delete buttons.Everything is working perfect.
<table class="table table-striped " style="width: 100%">
<tr ng-repeat="task in tasks" >
<td>{{$index}}</td>
<td>{{task.name}}</td>
<td>{{task.activity}}</td>
<td>{{task.time}}</td>
<td ><button type="button" ng-click="editRow($index)" class='btn btn-default '>Edit</button></td>
<td ><button type="button" ng-click="removeRow($index)" class='btn btn-default'>Delete</button></td>
</tr>
Index is very important to me ,because I'm accessing current task by index when edit or delete button is clicked.
Now, I'm trying to modify my code, I'm reading directives, and had idea to put everything from table row into a template inside directive, and than to call that directive in ng-repeat.
Something like this :
<tr ng-repeat="task in tasks" task-item = "task" >
</tr>
and directive :
app.directive('taskItem', function() {
return {
scope:{
taskItem: '='
},
restrict: 'A',
template: "<tr><td>{{$index}}</td>" +
"<td>{{taskItem.name}}</td>" +
"<td>{{taskItem.activity}}</td>" +
"<td>{{taskItem.time}}</td>" +
"<td><button type='button' ng-click='editRow($index)' class='btn btn-default '>Edit</button></td>" +
"<td><button type='button' ng-click='removeRow($index)' class='btn btn-default'>Delete</button></td>"+
"</tr>",
replace: false
};
});
Now I have issue , because index for each task is 1 and also edit and delete button click is not working .Maybe I have to write this template different, or try other approach.
So if anyone has any idea, please feel free to add comment.Thank You.
You can also pass in the index to your directive.
<tr ng-repeat="task in tasks" task-item="task" index="$index"></tr>
Then you can access that by adding it to the scope of your directive:
app.directive('taskItem', function() {
return {
scope:{
taskItem: '=',
index: '#'
},
restrict: 'A',
template: "<tr><td>{{index}}</td>" +
"<td>{{taskItem.name}}</td>" +
"<td>{{taskItem.activity}}</td>" +
"<td>{{taskItem.time}}</td>" +
"<td><button type='button' ng-click='editRow(index)' class='btn btn-default '>Edit</button></td>" +
"<td><button type='button' ng-click='removeRow(index)' class='btn btn-default'>Delete</button></td>"+
"</tr>",
replace: false
};
});
I've found working solution :) Apparently , there was a problem with something called "isolate scope" (don't judge me if I'm not using some of term correctly , I'm completely new to Angular )
So , I've removed scope part from directive
app.directive('taskItem', function() {
return {
restrict: 'A',
template: "<tr><td> {{$index}} </td>" +
"<td>{{task.name}}</td>" +
"<td>{{task.activity}}</td>" +
"<td>{{task.time}}</td>" +
"<td><button type='button' ng-click='editRow($index)' class='btn btn-default '>Edit</button></td>" +
"<td><button type='button' ng-click='removeRow($index)' class='btn btn-default'>Delete</button></td>"+
"</tr>",
replace: false
};
});
and made minor change in ng-repeater
<tr ng-repeat="task in tasks" task-item >
</tr>
And now , index displayed is different for each item, and also I can use both edit and delete button .

Calling function inside a directive in Angular

Sorry If this question has been asked before, but my issue is bit different and hope someone can help me out.
1) I have a Directive which has many buttons. I want to call a function on this buttons and inside a directive. But I don't know how.
// Directive for the login header to avoid the duplication of the code
angular.module('App').directive('mainHeader',function(){
return{
restrict: 'AE',
template:'<h1 class="logo"> My App </h1>'+
'<button class="btn btn-primary">New User</button>'+
'<button class="btn btn-primary">New Product</button>'+
'<span class="dropdown" on-toggle="toggled(open)">'+
'<a href class="dropdown-toggle">'+
'<img class="userProfile" src="" alt="User Profile">'+
'<b class="caret"></b>'+
'</a>'+
// Here on my profile ????
'<ul class="dropdown-menu pull-right">'+
'<li> My Profile </a> </li>'+
'<li class="divider"></li>'+
// Here on my logout ??????
// This does not work
'<li> <a href="" ng-click="logOut()"> Sign Out </li>'+
'</ul>'+
'</span>'
}
});
My controller
(function() {
var logOutController = function($scope){
$scope.logOut = function(){
// Want to call this
}
logOutController .$inject = ['$scope'];
angular.module('App').controller('logOutController ',logOutController );
}());
And my view will be only one line
<div main-header></div>
I don't know how to do this
Update 1: -
Please have a look at the Plunker
http://plnkr.co/edit/YONVyVvNm4pQGFMU6SkG?p=preview.
You will just need to add an isolate scope to your directive:
// Directive for the login header to avoid the duplication of the code
angular.module('App').directive('mainHeader', function () {
return {
restrict: 'AE',
template: '<h1 class="logo"> My App </h1>' +
'<button class="btn btn-primary">New User</button>' +
'<button class="btn btn-primary">New Product</button>' +
'<span class="dropdown" on-toggle="toggled(open)">' +
'<a href class="dropdown-toggle">' +
'<img class="userProfile" src="" alt="User Profile">' +
'<b class="caret"></b>' +
'</a>' +
// Here on my profile ????
'<ul class="dropdown-menu pull-right">' +
'<li> My Profile </a> </li>' +
'<li class="divider"></li>' +
// Here on my logout ??????
// This does not work
'<li> <a href="" ng-click="logOut()"> Sign Out </li>' +
'</ul>' +
'</span>',
scope: {
'logOut': '&onLogOut' //<- this ties your directive's logOut function to an attr on the HTML tag
}
}
});
Then you just modify your HTML to:
<div main-header on-log-out="logOut()"></div>
Plunker Example

ng-click inside bs-tooltip not working

I'm using angular-strap tooltip and inside I have link that should react to ng-click, but instead it's not responding.
.html
<span class="add-on input-group-addon" data-title="{{tooltips.date}}" bs-tooltip>
<i class="glyphicon glyphicon-calendar fa fa-calendar"></i> Dates
</span>
.js
$scope.tooltips = {
date: '<a class="btn btn-default" ng-click="select()">Select date</a>'
};
$scope.select = function() {
//doing something and works fine outside tooltip
}
In app .config() there is html set to true.
angular.extend($tooltipProvider.defaults, {
template: "static/lib/angular-strap/tooltip.tpl.html",
trigger: 'click',
html: true,
placement: 'bottom-left'
});
By using data-title along with html: true you are just passing some html, but it is not compiled by angular. If you want to use angular directives and data binding in your tooltip, use 'contentTemplate'; here is a working plunker: http://plnkr.co/LSl9gyHRKCMYoEGZZQei

Resources