Click event not defined via jquery - datatables-1.10

I have got the following DataTable with data and web bootstrap links displayed via the appropriate columns as shown below:
$(document).ready(function() {
$('#example').DataTable({
destroy: true,
"ajax":{
"url":"http://localhost:3000/tasks/list",
"dataSrc": ""
},
"columns":[
{"data":"title", "title":"Τίτλος"},
{"data":"description", "title":"Περιγραφή"},
{ "data": "ID",
"title": "Επισκόπηση",
"render": function(data, type, row, meta){
if(type === 'display'){
data = '<a class="btn btn-success btn-sm viewlink" role="button" data-toggle="modal" data-target="#viewModal" href="/tasks/todo/' + data + '">' + '<i class="fas fa-eye"></i>' + '</a>';
}
return data;
}
} ],
length: 20,
});
$('.viewlink').on("click", function(e){
console.log("Hello!!!");
});
});
Unfortunately when i press the bootstrap link button, i do not get any response via console.log.
Any idea that would be convenient to me!
Regards

You must use a delegated event handler, i.e
$('#example').on('click', '.viewlink', function(e) {
//
})
Reason: At the time your handler is declared no .viewLink's are present in DOM.

Related

Make ng-click behave like ng-changed

How can I make the ng-click behave like a ng-changed? Because every time I click the button it will send a data through AJAX. So the x.status value will changed.
This is my HTML
<button ng-click="status(x);" ng-switch="x.status">
<span ng-switch-when="orderer">SHOW</span>
<span ng-switch-when="orderer_hidden">HIDE</span>
<span ng-switch-when="creator">SHOW</span>
<span ng-switch-when="creator_hidden">HIDE</span>
</button>
The ng-switch will trigger only when I refresh the page.
UPDATED
This is the script
$scope.status = function(data){
$http({
method: "GET",
url: Ajax_call.ajaxurl,
params: {
id: data.id,
status: data.status,
action: "status_changed"
}
});
}

angularjs datatables are not responsive

I'm working with angular datatables, and I have to states : #/app/configurations/formations and #/app/configurations/filieres, so when I switch between these two states I have some issues related to presentation as following :
the first time when I access #/app/configurations/formations this is how it looks :
but when I access some other state for example : #/app/configurations/filieres my datatable doesn't expand in the whole page :
and this behavior remains for all my datatables in my application, so I have always to refresh the page to make the datatable expand in the whole page.
this is how I build all my datatables :
var vm = this;
vm.dtOptions = DTOptionsBuilder.fromSource("http://localhost:8080/diplomes")
.withPaginationType('full_numbers')
.withBootstrap()
// Active Responsive plugin
.withOption('responsive', false)
.withOption('initComplete', function(settings) {
// Recompiling so we can bind Angular directive to the DT
$compile(angular.element('#' + settings.sTableId).contents())($scope);
});
vm.dtColumns = [
DTColumnBuilder.newColumn('codeDiplome').withTitle('ID Diplome'),
DTColumnBuilder.newColumn('nom').withTitle('NOM Diplome'),
DTColumnBuilder.newColumn(null).withTitle('Actions').notSortable()
.renderWith(function(data, type, full, meta) {
if (true) {
return '<button class="btn btn-bl btn-success btn-ef btn-ef-5 btn-ef-5b mb-10" ng-click="openEditModal('+data.codeDiplome+')"><i class="fa fa-edit"></i> <span>'+$scope.update+'</span></button> '
+ '<button class="btn btn-danger btn-ef btn-ef-5 btn-ef-5b mb-10" ng-click="openDeleteModal('+data.codeDiplome+')"><i class="fa fa-trash"></i> <span>'+$scope.delete+'</span></button>';
} else {
return '';
}
})
];
The solution was to add special class to the datatable for example dt-responsive and then we assign a style to this class width: 100%!important

angularjs remove from array without knowing index

I have an arraylist which is used to display a leave request workflow. If a vacation leave request is currently saved as a draft, the request is added to my draft list, however if it's been submitted from a modal form to be approved it would need to be removed from the draft list and added to the approval list. My question is the list are external to my form and my form has does not know the index of the list. When I update my request from draft to approve, how do I remove it from the draft list and add it to the approved list without knowing the index.
The first thought that came to mind was to create a unique attribute with the objects database pk like so data-approval="7"and select it with some sort of jquery function and remove the item from the list, but from what I read, that isn't the angular way to do things. So without knowing the index how would I remove an item from my list in angularjs?
Example of loop.
<ul>
<li ng-repeat="e in pendingApprovals" data-approval="{{e.id}}">
<div class="alert alert-info">
<h5>{{e.title}}</h5>
<div>
{{e.type}}
</div>
{{e.start | date:'MM/dd/yyyy - hh:mm a'}}
{{e.end | date:'MM/dd/yyyy - hh:mm a'}}
<a ng-click="rejectClick(e.id)" class="btn btn-danger btn-xs btn-block">
<i class="fa fa-thumbs-down fa-1"></i>
Reject
</a>
<a ng-click="approveClick($index, e.id)" class="btn btn-success btn-xs btn-block">
<i class="fa fa-thumbs-up fa-1"></i>
Approve
</a>
</div>
</li>
</ul>
JS
modalInstance.result.then(function(formData) {
$http.post('./calendar/save.json', formData).then(
function(response) {
if(formData.update) {
$scope.refresh();
console.log('refresh')
angular.element(elem[0].querySelector('[data-unsubmitted="' + response.data.id + '"]')).remove();
} else {
$scope.events.push(response.data);
$scope.pendingApprovals.push(response.data);
}
}, function(response) {
console.log('failure ' + response)
// called asynchronously if an error
// occurs
// or server returns response with an
// error status.
});
}, function() {
$log.info('Modal dismissed at: ' + new Date());
});
It appears as if filters as #ste2425 was in fact the solution.
modalInstance.result.then(function(formData) {
$http.post('./calendar/save.json', formData).then(
function(response) {
if(formData.update) {
$scope.refresh();
var items = $scope.pendingApprovals;
var item = $filter('filter')(items, {id: response.data.id}, true)[0];
var index = items.indexOf(item);
$scope.pendingApprovals.splice(index,1);
} else {
$scope.events.push(response.data);
$scope.pendingApprovals.push(response.data);
}
}, function(response) {
console.log('failure ' + response)
// called asynchronously if an error
// occurs
// or server returns response with an
// error status.
});
}, function() {
$log.info('Modal dismissed at: ' + new Date());
});
I also found help from this SO question how to get index position of an array item in controller passing a value in angularjs

How to register the event in $scope using handlebar in twitter typeahead

I am using the latest twitter typeahead using custom templates using AngularJS.
I am able to get the desired output but I have a button in the custom templates that appears when we enter anything in the dropdown.
Here is the plunker : http://plnkr.co/edit/u5zkXhry0bCu6u5r0WuP?p=preview
Now when I click on the Add button the event is not getting fired. I think the event is not getting registered in the $scope. How can I do this over here ?
$('#prependedInput').typeahead({
hint: true,
highlighter: function (x) { return x; },
minLength: 3,
},
{
name: 'members',
displayKey: 'value',
source: getUserSearchData,
templates: {
suggestion: Handlebars.compile('{{member}}')
}
});
Handlebars.registerHelper('member', function (items) {
var item = this;
var items = '<li><a><div class="row"><img style="height: 40px; float:left" src=' + getAvatarUrl(item) + ' /><span style="padding: 0.5em; float:left;"> ' + getDisplayName(item) + '</span><button class="btn btn-sm pull-right" ng-click="confirmAddDialog(' + item.id + ')">Add</button></div></a></li>';
return new Handlebars.SafeString(items)
});
I do have one function to fire a modal popup.
$scope.confirmAddDialog = function (userId) {
flashSvc.add('we are hit...');
};
How can I register the event using template.

AngularJS: Refactoring a confirmation modal directive

I need some advice on refactoring a modal directive I have. I am just getting started with directives, so any other approach to my problem is welcome.
My program needs a confirmation modal, where we can confirm or cancel the desired action. It will appear in many places and needs to be able to have a programmable button. Cancel is consistent in that it will only hide the modal, the confirmation button needs to perform whatever action required.
I am currently using $rootScope to show / hide / configure the modal. Is this a bad idea? Please tell me.
This is what I am working with right now (roughly, as I have cut out a lot of the other unnecessary code):
index.html
<!doctype html>
<html lang="en">
<head>
<title>My App</title>
</head>
<body ng-controller="MenuCtrl">
<confirmmodal ng-show="$root.confirmModal.isVisible"></confirmmodal>
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
<div ng-view></div>
<!-- build:js scripts/main.js -->
<script data-main="scripts/main" src="lib/requirejs/require.js"></script>
<!-- endbuild -->
</body>
</html>
So my modal sits atop the ng-view and can be called from anywhere. It is inside a pseudo global controller, called MenuCtrl.
Here is the modal directive code:
directives.js
/* Confirm Modal */
.directive('confirmmodal', [function() {
return {
restrict: 'E',
templateUrl: 'view/templates/modal-confirm.tpl.html'
};
}])
It serves as a template for the following code:
modal-confirm.tpl.html
<!-- Confirm Modal Template -->
<div class="overlay">
<div class="overlay-content extended">
<span>{{$root.confirmModal.content}}</span>
<div class="buttons">
<button class="btn btn-default" ng-click="$root.confirmModal.secondary.action()">{{$root.confirmModal.secondary.content}}</button>
<button class="btn btn-primary" ng-click="$root.confirmModal.primary.action()">{{$root.confirmModal.primary.content}}</button>
</div>
</div>
</div>
I set a bunch of defaults in the app.run function:
app.js
app.run(['$rootScope', function ($rootScope) {
_.extend($rootScope, {
confirmModal: {
isVisible: false,
content: '',
primary: {
action: function() {
console.log('hello world');
},
content: 'Submit'
},
secondary: {
action: function() {
$rootScope.confirmModal.isVisible = false;
},
content: 'Cancel'
}
}
});
}]);
So I've also coded a modal trigger directive, the idea being that I can create different triggers that perform different actions with the modal.
directives.js
/* Resolve Event */
.directive('resolveevent', ['RequestService', '$location', function (RequestService, $location) {
return {
restrict: 'A',
scope: {
eventtype: '#',
eventid: '#',
index: '#'
},
controller: ['$scope', function($scope) {
$scope.remove = function(id) {
// remove the event from the events array
$scope.$parent.$parent.$parent.$parent.events.splice(id, 1);
},
$scope.config = function(config) {
_.extend($scope.$root.confirmModal, config);
},
$scope.isVisible = function() {
$scope.$apply(function() {
$scope.$root.confirmModal.isVisible = true;
});
}
}],
link: function( $scope, element, attrs ) {
var config = {
content: 'Are you sure you wish to resolve this event?',
primary: {
action: function() {
var config = {
url: '/Events/' + $scope.eventid,
method: 'PUT',
data: {
event_status: 'resolved'
},
cache: false
}
/* Update event with resolved status */
RequestService.makeApiRequest(config).success(function(response) {
$scope.$root.confirmModal.isVisible = false;
$scope.remove($scope.index);
});
},
content: 'Resolve Event'
}
}
element.on('click', function() {
if (!$scope.$root.confirmModal.isVisible) {
$scope.config(config);
$scope.isVisible();
}
});
}
}
}]);
And then I use a button on the view where my ng-repeat is found which is able to trigger the modal:
eventlist.html
<li ng-repeat="event in events">
<p>Event: {{ event.number }}</p>
<p>Group: {{ event.group_name }}</p>
<p>Record Date: {{ event.event_date | moment: 'MM/DD/YYYY h:mm A' }}</p>
<button resolveevent index="{{$index}}" eventid="{{ event.number }}" class="btn btn-default">Resolve</button>
</li>
This is what I've got, and it is working, however it seems like overkill, inefficient, and a nightmare to maintain. Can anyone chime in on a way to improve this? I appreciate any help, thanks in advance.
You can have a look at the bootstrap-ui project : http://angular-ui.github.io/bootstrap/
If you're using Bootstrap 3, be careful about the templates, and use the version without them. You can download bootstrap3 compliant templates here : https://github.com/angular-ui/bootstrap/tree/bootstrap3_bis2_modalPatch
A simple directive to confirm:
/**
* A generic confirmation for risky actions.
* Usage: Add attributes: ng-really-message="Really?" ng-really-click="takeAction()" function
*/
angular.module('app').directive('ngReallyClick', [function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.bind('click', function() {
var message = attrs.ngReallyMessage;
if (message && confirm(message)) {
scope.$apply(attrs.ngReallyClick);
}
});
}
}
}]);
My method might not be according to best practises, but I usually end up creating dedicated service that both has access to modal's scope and manipulates dom. Think of it as self injecting directive.
Here's the modal's container html (uses bootstrap's styling):
<div class="modal-backdrop"></div>
<div class="modal fade">
<div class="modal-dialog" ng-style="{width: width}">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" ng-click="close()" aria-hidden="true">×</button>
<h4 class="modal-title">{{title}}</h4>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button ng-repeat="(name, callback) in buttons" type="button" ng-click="callback()">{{name}}</button>
</div>
</div>
</div>
</div>
Then there's pseudo code of the DialogService:
.service('DialogService', function($compile, $http, $rootScope) {
this.open = function(options) {
//options contain various properties
//e.g. title, width, template or templateUrl, button map with callbacks
loadModalContainer()
.then(loadModalBody)
.then(init);
function init() {
modal = $('body').append(containerHtml).find('.modal');
modal.append(bodyHtml);
scope = (options.scope || $rootScope).$new();
if (options.controller) $controller(options.controller, {$scope: scope});
$compile(modal)(scope);
listenForEscKey();
}
function close() {
//clean up event listeners
//
if (options.onClose) options.onClose();
scope.$destroy();
$('body').find('.modal,.modal-backdrop').remove();
}
}
});
Of course, because of the async nature of the service, you have to implement some auto-close logic if second modal pops-up. From there is really easy, you can define concrete dialogs as separate services to abstract away the details:
.service('TermsModal', function(DialogService) {
this.open = function(acceptCallback, declineCallback, scope) {
DialogService.open({
templateUrl: '',
width: '',
buttons: {
accept: acceptCallback,
decline: declineCallback
},
scope: scope
});
}
})
Then from any controller you can open modal with an one-liner: TermsModal.open(acceptCallback, declineCallback, $scope)
There are several issues. First of all, it would be great to use transclusion, since now modal's child scope is littered with title, buttons, width properties.
Another thing is that I pass around modal body's width, but that's just my laziness (I cannot style bootstraps modal body width properly since it's hardcoded).
Also, I pass around local scopes from controllers because very often modal's body content is in one or another way related to the controller that invokes the modal. If, say, we have ItemController with item as scope property and we have an edit button to edit item's value in a modal, the child scope has to know about the model it's dealing with. So either it's passing around scope or passing needed values directly in options. I prefer scope because that gives more flexibility and with child scope intialization it is really hard to mess up orginal model.
All in all, the power and flexibility this set-up gives justifies the fact that service is messing a bit with the DOM. Your rootScope becomes free of global state (the service manages its own state without giving details to the outside world) and your main template is free of modal partials/directives/whatever that may or may not be used.
I have created a small confirmation directive which, opens a modal and executes the code you want, if the modal is confirmed:
app.html
<button type="button" class="btn btn-default"
nait-confirm-click
confirm="Do you really want to remove this record?"
confirm-if="user.disabled == true"
do="remove(user)">
Remove
</button>
script.js
angular
.module('xyz', ['ui.bootstrap'])
.directive('naitConfirmClick', function($modal, $parse) {
return {
restrict: 'EA',
link: function(scope, element, attrs) {
if (!attrs.do) {
return;
}
// register the confirmation event
var confirmButtonText = attrs.confirmButtonText ? attrs.confirmButtonText : 'OK';
var cancelButtonText = attrs.cancelButtonText ? attrs.cancelButtonText : 'Cancel';
element.click(function() {
// action that should be executed if user confirms
var doThis = $parse(attrs.do);
// condition for confirmation
if (attrs.confirmIf) {
var confirmationCondition = $parse(attrs.confirmIf);
if (!confirmationCondition(scope)) {
// if no confirmation is needed, we can execute the action and leave
doThis(scope);
scope.$apply();
return;
}
}
$modal
.open({
template: '<div class="modal-body">' + attrs.confirm + '</div>'
+ '<div class="modal-footer">'
+ '<button type="button" class="btn btn-default btn-naitsirch-confirm pull-right" ng-click="$close(\'ok\')">' + confirmButtonText + '</button>'
+ '<button type="button" class="btn btn-default btn-naitsirch-cancel pull-right" ng-click="$dismiss(\'cancel\')">' + cancelButtonText + '</button>'
+ '</div>'
})
.result.then(function() {
doThis(scope);
scope.$apply()
})
;
});
}
};
})
;
Now, if you click on the button with the nait-confirm-click it opens a modal with two buttons and the text you have passed by the confirm attribute. If you click the cancel button, nothing will happen. If you confirm by clicking "OK", the expression, which you have passed by the do attribute, will be executed.
If you pass an expression in the optional confirm-if attribute, the modal will only be opened if the expression is true. If the expression is false, the action will be executed without asking.
I hope this snippet will help someone ;)

Resources