Edit and deleteRow functions in code not called when button clicked - angularjs

I am population angular-datatable using server side response . Issue is i am not able to call the function in html added through renderWith(actionsHtml).
var vm = this;
vm.edit = edit;
vm.deleteRow = deleteRow;
var draw = 0;
vm.dtOptions = DTOptionsBuilder.newOptions()
.withOption('serverSide', true)
.withOption('ajax', function(data, callback, settings) {
// make an ajax request using data.start and data.length
$http.post('/getProduct/api/call', {
draw: draw,
store_id: Session.sessionuserid(),
limit: data.length,
offset: data.start,
contains: data.search.value
}).success(function(res) {
// map your server's response to the DataTables format and pass it to
// DataTables' callback
draw = res.draw;
callback({
recordsTotal: res.meta,
recordsFiltered: res.meta,
draw: res.draw,
data: res.data
});
});
}).withDataProp('data');
vm.dtColumns = [
DTColumnBuilder.newColumn('name').withTitle('PRODUCT NAME'),
DTColumnBuilder.newColumn('price').withTitle('PRICE'),
DTColumnBuilder.newColumn('offer_flag').withTitle('Weekly Special'),
DTColumnBuilder.newColumn(null).withTitle('Actions').notSortable()
.renderWith(actionsHtml)
];
function actionsHtml(data, type, full, meta) {
return '<button class="btn btn-warning" ng-click="showCase.edit(' + data.id + ')">' +
' <i class="fa fa-edit"></i>' +
'</button> ' +
'<button class="btn btn-danger" ng-click="showCase.deleteRow(' + data.id + ')">' +
' <i class="fa fa-trash-o"></i>' +
'</button>';
}
These functions are not called when buttons pressed
function edit(id) {
console.log(id);
TempStore.addID(id);
$location.path('/editproduct');
}
function deleteRow(id) {
var msgbox = $dialog.messageBox('Delete Product', 'Are you sure?', [{label: 'Yes, I\'m sure', result: 'yes'}, {label: 'Nope', result: 'no'}]);
msgbox.open().then(function(result) {
if (result === 'yes') {
$scope.removeproduct = Restdata.remove({sailsModel: 'products', id: id}, function() {
$window.location.reload();
});
}
});
}
;
Here is my HTML :

After your DataTable is rendered, you need to recompile with $compile in order to bind your $scope and angular directives to the produces HTML:
vm.dtOptions = DTOptions.newOptions()
.withOption('createdRow', createdRow)
... // other options
function createdRow(row, data, dataIndex) {
// Recompiling so we can bind Angular directive to the DT
$compile(angular.element(row).contents())($scope);
}
See the documentation on how to bind angular directives.

Related

ng-click event binding not working inside angular-datatables

I am using angular-datatables for listing student information. I want to implement server-side ajax implementation for every search, sorting, paging etc rather than fetch all data and repeat the data using angularjs. sorting, searching, paging is working fine. But I am unable to bind ng-click event when click on specific row actions.
This is my view:
This is my javascript source code:
<div ng-app="myApp">
<div ng-controller="OrganizationController">
<table id="entry-grid" datatable="" dt-options="dtOptions"
dt-columns="dtColumns" class="table table-hover"></table>
</div>
</div>
<script>
var app = angular.module('myApp',['datatables']);
app.controller('OrganizationController', BindAngularDirectiveCtrl);
function BindAngularDirectiveCtrl($scope, $compile, DTOptionsBuilder, DTColumnBuilder) {
var vm = this;
vm.message = '';
vm.edit = edit;
vm.dtInstance = {};
vm.persons = {};
$scope.dtColumns = [
DTColumnBuilder.newColumn("organization_name").withOption('organization_name'),
DTColumnBuilder.newColumn(null).withTitle('Actions').notSortable()
.renderWith(actionsHtml)
]
$scope.dtOptions = DTOptionsBuilder.newOptions().withOption('ajax', {
dataSrc: "data",
url: "organizations",
type:"get"
})
.withOption('processing', true) //for show progress bar
.withOption('serverSide', true) // for server side processing
.withPaginationType('full_numbers') // for get full pagination options // first / last / prev / next and page numbers
.withDisplayLength(2) // Page size
.withOption('aaSorting',[0,'asc'])
function edit() {
console.log('hi')
}
function actionsHtml(data, type, full, meta) {
vm.persons[data.id] = data;
return '<button class="btn btn-warning" ng-click="edit()">' +
' <i class="fa fa-edit"></i>' +
'</button>';
}
}
</script>
You didn't add withOption("rowCallback",fn)
<script>
var app = angular.module('myApp',['datatables']);
app.controller('OrganizationController', BindAngularDirectiveCtrl);
function BindAngularDirectiveCtrl($scope, $compile, DTOptionsBuilder, DTColumnBuilder) {
var vm = this;
vm.message = '';
vm.edit = edit;
vm.dtInstance = {};
vm.persons = {};
$scope.dtColumns = [
DTColumnBuilder.newColumn("organization_name").withOption('organization_name'),
DTColumnBuilder.newColumn(null).withTitle('Actions').notSortable()
.renderWith(actionsHtml)
]
$scope.dtOptions = DTOptionsBuilder.newOptions().withOption('ajax', {
dataSrc: "data",
url: "organizations",
type:"get"
})
.withOption('rowCallback', rowCallback)
.withOption('processing', true) //for show progress bar
.withOption('serverSide', true) // for server side processing
.withPaginationType('full_numbers') // for get full pagination options // first / last / prev / next and page numbers
.withDisplayLength(2) // Page size
.withOption('aaSorting',[0,'asc'])
function edit() {
console.log('hi')
}
function actionsHtml(data, type, full, meta) {
vm.persons[data.id] = data;
return '<button class="btn btn-warning" ng-click="edit()">' +
' <i class="fa fa-edit"></i>' +
'</button>';
}
function rowCallback(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
// Unbind first in order to avoid any duplicate handler (see https://github.com/l-lin/angular-datatables/issues/87)
$('td', nRow).unbind('click');
$('td', nRow).bind('click', function()
{
$scope.$apply(function() {
alert("You've clicked row," + iDisplayIndex);
});
});
return nRow;
}
}
</script>
If we want to bind a click event to specific DOM element in angular datatable row find(jQuery)that element using any CSS selector. For example -
HTML
<table id='table' datatable [dtOptions]="dtOptions" class="table table-sm table-striped table-bordered" cellspacing="0" width="100%">
Angular(v4) Component-
export class ExampleComponent implements OnInit {
dtOptions: DataTables.Settings = {};
ngOnInit() {
//Starts Angular jQuery DataTable server side processing settings
let ajaxSettings: any = {
settings: {
ajax: {
...
},
serverSide: true,
searchDelay: 800,
deferRender: true,
processing: true,
autoWidth: false,
stateSave: false,
searching: true,
aoColumns: [
//Table column definition
{
//Action Column
sTitle: 'Action',
sWidth: "20%",
bSearchable: false,
bSortable: false,
mRender: (data, type, full) => {
return "<a href='javascript:void(0);' class='custombtn btn btn-sm btn-primary'><span class='fa fa-paper-plane-o'></span>Action Button</a>";
}
}
],
fnServerParams: function (data) {
},
initComplete: () => {
},
rowCallback: (row: Node, data: any[] | Object, index: number) => {
const self = this;
// Unbind first in order to avoid any duplicate handler
// (see https://github.com/l-lin/angular-datatables/issues/87)
var element = $('td', row).find('a.custombtn');
if (element) {
element.unbind('click');
element.bind('click', () => {
self.someClickHandler(data, index);
});
}
return row;
}
}
};
this.dtOptions = ajaxSettings.settings;
//Ends Angular jQuery DataTable server side processing settings
}
//Will be called on click of anchor tag which has the class "custombtn"
someClickHandler(info: any, index: number): void {
alert(JSON.stringify(info) + ' index =>' + index);
}
}

http.put not updating correct database column in nodejs app

I have a database [|id | text(string) | complete(boolean)],
and I'm trying to update last column to true/false, depending upon action chosen. But my code is updating text column to true/false.
html code
<div class="container">
<div class="header">
<h1> Table </h1>
</div>
<div ng-app="nodeTodo" ng-controller="mainController">
<table>
<tr ng-repeat="x in todoData">
<td>{{ x.id }}</td>
<td>{{ x.text }}</td>
<td>{{ x.complete }}</td>
<td>
<div class="btn-group">
<button type="button" class="btn btn-danger">Action</button>
<button type="button" class="btn btn-danger dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu" role="menu">
<li ng-repeat="choice in actions">
<a ng-click="updateAssign(x.id, x.text, choice)"> {{choice}} </a>
</li>
</ul>
</div>
</td>
</tr>
</table>
</div>
</div>
mainController
angular.module('nodeTodo', [])
.controller('mainController', function($scope, $http) {
$scope.formData = {};
$scope.todoData = {};
$scope.actions = [
"true",
"false"
];
$scope.action = false;
// Get all todos
$http.get('/api/v1/todos')
.success(function(data) {
$scope.todoData = data;
console.log(data);
})
.error(function(error) {
console.log('Error: ' + error);
});
// Create a new todo
$scope.createTodo = function(todoID) {
$http.post('/api/v1/todos', $scope.formData)
.success(function(data) {
$scope.formData = {};
$scope.todoData = data;
console.log(data);
})
.error(function(error) {
console.log('Error: ' + error);
});
};
// Delete a todo
$scope.deleteTodo = function(todoID) {
$http.delete('/api/v1/todos/' + todoID)
.success(function(data) {
$scope.todoData = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
// update assignment
$scope.updateAssign = function(todoID, textOld, choice) {
if (String(choice) == "true") {
var boolchoice = true;
}
else {
var boolchoice = false;
}
console.log('Debug1:' + textOld + ' ' + boolchoice);
$http.put('/api/v1/todos/' + todoID, {text: textOld, complete: boolchoice})
.success(function(data) {
$scope.todoData = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
});
Router.put
router.put('/api/v1/todos/:todo_id', function(req, res) {
var results = [];
// Grab data from the URL parameters
var id = req.params.todo_id;
// Grab data from http request
var data = {text: req.body.text, complete: req.body.complete};
console.log("Debug:" + data.text + " " + data.complete);
// Get a Postgres client from the connection pool
pg.connect(connectionString, function(err, client, done) {
// SQL Query > Update Data
client.query("UPDATE items SET text=($1), complete=($2) WHERE id=($3)", [data.text, data.complete, id]);
// SQL Query > Select Data
var query = client.query("SELECT * FROM items ORDER BY id ASC");
// Stream results back one row at a time
query.on('row', function(row) {
results.push(row);
});
// After all data is returned, close connection and return results
query.on('end', function() {
client.end();
return res.json(results);
});
// Handle Errors
if(err) {
console.log(err);
}
});
As a read somewhere better approach to update using $scope.var in http.put, but I'm not sure how to do that.
I have started with this tutorial as a base point.
Made it work after some effort. Passing scope variable to router.put worked.
Changes in Controller
$scope.updateAssign = function(todoID, text, choice) {
if (String(choice) == "true") {
$scope.action = true;
}
else {
$scope.action = false;
}
// console.log('Debug1:' + text + ' ' + choice);
$http.put('/api/v1/todos/' + todoID, {text: text, complete: $scope.action})
.success(function(data) {
$scope.todoData = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};

How to start upload file in Angular JS?

I use Angular JS library angular-file-upload.
I moved init FileUploader code from controller to factory method:
.factory('UploadFilesHash', ['FileUploader', function (FileUploader) {
var uploader;
return {
uploadInit: function (data){
uploader = new FileUploader({
url: '/upload/',
formData: data,
alias: 'files',
autoUpload: true
});
// FILTERS
uploader.filters.push({
name: 'imageFilter',
fn: function (item /*{File|FileLikeObject}*/, options) {
var type = '|' + item.type.slice(item.type.lastIndexOf('/') + 1) + '|';
return '|jpg|png|jpeg|bmp|gif|'.indexOf(type) !== -1;
}
});
// CALLBACKS
uploader.onWhenAddingFileFailed = function (item /*{File|FileLikeObject}*/, filter, options) {
//console.info('onWhenAddingFileFailed', item, filter, options);
};
});
}
So, in controller I do inject this factory and call init function:
Controller:
$scope.startFromView = function (){
UploadFilesHash.uploadInit(data);
}
HTML:
<span ng-click="startFromView()">
<input type="file" nv-file-select="" uploader="uploader" multiple />
</span>
So, problem is that I call function startFromView() then there is no file upload. Earlier this code was at controller and all work.

AngularJS View Not Updating Using Defer and Factory

I am currently having an issue where when I try to create a new setting my view is not being updated until I refresh the page. Can anyone point me into the right direction? If I am going about this the wrong way please let me know a better way to do this.
app.factory('SettingsFactory', function ($http, $q) {
//$scope.settingData = {}
return {
getAllOptionsAsync: function(callback) {
var deferred = $q.defer();
$http.get('/api/settings').success(callback);
},
deleteOptionAsync: function(id) {
//console.log('reached');
var deferred = $q.defer();
$http.delete('/api/settings/' + id);
},
createOptionAsync: function(settingData) {
var deferred = $q.defer();
$http.post('/api/settings', settingData).success(function(data) { console.log(data);
deferred.resolve(data);
// console.log(deferred.promise);
return deferred.promise;
});
}
};
});
var controllers = {};
controllers.SettingsController = function($scope, SettingsFactory) {
//$scope.settings = SettingService.list();
SettingsFactory.getAllOptionsAsync(function(results) {
//console.log(results);
$scope.settings = results;
});
$scope.create = function() {
// console.log('called');
// console.log($scope.formData);
SettingsFactory.createOptionAsync($scope.formData).then(function(data) {
console.log(data);
$scope.settings = data;
});
}
$scope.delete = function(id) {
//console.log(id.entity._id);
SettingsFactory.deleteOptionAsync(id.entity._id);
}
$scope.gridOptions = {
data: 'settings',
multiSelect: false,
columnDefs: [
{field: 'option'},
{field: 'value'},
{displayName: 'Edit', cellTemplate: '<button id="editBtn" type="button" class="btn btn-primary" ng-click="open(settings._id)" >Edit</button> <button id="deleteBtn" type="button" class="btn btn-primary" ng-click="delete(row)" >Edit</button> '}
]
};
}
Inside of the then or anytime you are updating the scope in a callback you need to wrap the $scope.settings=data with a scope.apply.
$scope.$apply(function() {
$scope.settings=data;
});
Typed out on phone so there might be an error.

AngularJS inline edit inside of ng-repeat

Im working with AngularJS to display a table of app keys (app identifiers) and I would like to use an edit button to display a small form in that table row. Then the user can edit the fields and click "save" or "cancel"
Demo: http://jsfiddle.net/Thw8n/
I have the inline form working great. I click edit and a form appears. Cancel works great too.
My problem is
How do I connect the save button with a function that will make a $http call to an API
How do I get the data from that row to send to the $http call?
How do I disable editMode once the call comes back?
Here is the actual code Im using in my controller (in the JSFiddle Im not able to make the http call). The first $http fills out the form, the editAppKey function is what is called by the save button.
function AppKeysCtrl($scope, $http, $location) {
$http({
method: 'POST',
url: 'http://' + $location.host() + ':1111/sys/appkey/save',
data: {
// How do I get the data?
}
}).
success(function(data, status, headers, config) {
$scope.appkeys = data;
}).
error(function(data, status, headers, config) {
$scope.appkeys = [{ "appkey" : "ERROR", "name" : "ERROR", "created" : "ERROR" }];
});
$scope.editAppKey = function() {
$http({
method: 'POST',
url: 'http://' + $location.host() + ':1111/sys/appkeys'
}).
success(function(data, status, headers, config) {
alert("Success!");
$scope.editMode = false;
}).
error(function(data, status, headers, config) {
alert("There was an error.");
});
}
}
When we press on "Edit" button and change one of fields , we also change our main model appkeys. Its mean that on "Cancel" we need restore old model.
Its mean that we need at least:
So this is a snippets of HTML:
<td>
<button type="submit" data-ng-hide="editMode" data-ng-click="editMode = true; editAppKey(entry)" class="btn btn-default">Edit</button>
<button type="submit" data-ng-show="editMode" data-ng-click="editMode = false; saveField()" class="btn btn-default">Save</button>
<button type="submit" data-ng-show="editMode" data-ng-click="editMode = false; cancel()" class="btn btn-default">Cancel</button>
</td>
And our controller:
$scope.newField = {};
$scope.editing = false;
$scope.appkeys = [
{ "appkey" : "0123456789", "name" : "My new app key", "created" : tmpDate },
{ "appkey" : "abcdefghij", "name" : "Someone elses app key", "created" : tmpDate }
];
$scope.editAppKey = function(field) {
$scope.editing = $scope.appkeys.indexOf(field);
$scope.newField = angular.copy(field);
}
$scope.saveField = function() {
if ($scope.editing !== false) {
$scope.appkeys[$scope.editing] = $scope.newField;
$scope.editing = false;
}
};
$scope.cancel = function() {
if ($scope.editing !== false) {
$scope.appkeys[$scope.editing] = $scope.newField;
$scope.editing = false;
}
};
Demo Fiddle
[EDIT]
I you want to edit several rows at once, use array of newFields instead $scope.newField
You can pass e.g. current index as a parameter to the editAppKey() function:
... data-ng-click="editAppKey($index)"
and in the JS file:
$scope.editAppKey = function(index) {
window.console.log(appkeys[index]); // do what ever you want
}
as for the disabling once the request is back. If I undestand, you want to allow only one time edit and after editAppKey() is called once on some row, disable it, right? If so, maybe something like
<button type="submit" data-ng-hide="editMode" data-ng-click="editMode = true" class="btn btn-default"
data-ng-disabled="entry.isDisabled">Edit</button>
and in the editAppKey() function, something like
$scope.editAppKey = function(index){
$http.post(url, data).onsuccess(function(){
$scope.appkeys[index].isDisabled = true;
});
In case someone need multiple edit at once:
Just do the following:
on html cancel button, pass the index
data-ng-click="editMode = false; cancel($index)"
on JS side:
1) $scope.newField = {}; to $scope.newField = [];
2) inside editAppKey function, $scope.newField = angular.copy(field); to $scope.newField[$scope.editing] = angular.copy(field);
3) change the saveField function to:
$scope.saveField = function(index) {
$scope.appkeys[$scope.editing] = $scope.newField;
};
4) change the cancel function to:
$scope.cancel = function(index) {
$scope.appkeys[index] = $scope.newField[index];
$scope.editing = false;
};
Fiddle

Resources