Button Actions Quit Working When Using Web Service
Button Actions Quit Working When Using Web Service
I am using SmartAdmin Angular 5 framework 1.9.1, which provides DataTables capabilities. I have installed DataTables 1.10.18, and Select 1.2.6.
My app can use either test data, or data from a web service. When I use test data, all works fine with the Delete and Archive buttons - meaning, the button action events are fired. But, when using web service data, the Delete and Archive buttons do not fire the button actions.
You can try my app at:
tanglemydata.com
To see problem, do this:
- Use latest Chrome or Firefox (no mobile), make browser window wide enough to see the buttons (as shown below).
- Login - I've hard-coded in the login credentials.
- Click Notifications in left pane.
- Expand General Messages, wait for table to display. Data comes from web service.
- Select one or multiple rows.
- Click Delete or Archive buttons - you should see a YES/NO dialog, it does not work.
- Expand Colleagues, then expand Colleague Messages, wait for table to display. Test data is hard-coded.
- Select one or multiple rows.
- Click Delete or Archive buttons - you should see a YES/NO dialog, it does work.
Looking at the .ts code line 145, you see that I go through a table.clear().rows.add(data_from_web_service).draw() operation. I tried it w/wo clear(), but same problem.
I have the following component.ts code:
import { NgModule, Component, OnInit, Injectable, Inject, ViewChild, DoCheck } from '@angular/core';
import { Router } from '@angular/router';
import { FormGroup, FormControl } from '@angular/forms';
import { FadeInTop } from "../shared/animations/fade-in-top.decorator";
import { NotificationsService } from './notifications.service';
import { NotificationService } from '../shared/utils/notification.service';
import { DatatableComponent } from '../shared/ui/datatable/datatable.component';
declare let $:any;
@FadeInTop()
@Component({
selector: 'sa-datatables-case',
templateUrl: './notifgenmsg.component.html',
styleUrls: ['../../assets/css/tmd_basic.css']
})
@Injectable()
export class NotifGenMsgComponent implements OnInit, DoCheck {
@ViewChild(DatatableComponent) ngxDatatableComponent: DatatableComponent;
public genMsgs: any;
constructor(
private router: Router,
private notificationsService: NotificationsService, //TMD version
private notificationService: NotificationService //SA version used for dialogs
) {}
ngOnInit() {
//###console.log("NotifGenMsgComponent ngOnInit - ENTRY");
//this allows the router.navigate to re-call this component, providing fresh data
this.router.routeReuseStrategy.shouldReuseRoute = function(){
return false;
};
//this kicks-off the web service call for data, when data is returned the (val) block is reached then refreshDataTable() is called
this.getNotifGenMsgData();
//###console.log("NotifGenMsgComponent ngOnInit - EXIT");
}
ngDoCheck() {
//this is called after ngOnInit - see https://codecraft.tv/courses/angular/components/lifecycle-hooks/
}
handleButtons() {
//###console.log('handleButtons');
if($(this.ngxDatatableComponent)) {
if($(this.ngxDatatableComponent).DataTable) {
console.log('processing button clicks');
const ngxDataTable = $($(this.ngxDatatableComponent).DataTable.tables()).DataTable();
const deleteBtnNum = 4;
const archiveBtnNum = 5;
ngxDataTable.button(deleteBtnNum).action(() => { //lambda expression provides access to outer this, but inner this is not accessible
//###console.log( this.text() +' button was clicked' ); //will not work when using lambda expression
console.log('Delete button clicked');
const selection = ngxDataTable.rows({ selected: true } ).data().toArray();
this.doSelection(selection, 'Delete');
});
ngxDataTable.button(archiveBtnNum).action(() => { //lambda expression provides access to outer this, but inner this is not accessible
//###console.log( this.text() +' button was clicked' ); //will not work when using lambda expression
console.log('Archive button clicked');
const selection = ngxDataTable.rows({ selected: true } ).data().toArray();
this.doSelection(selection, 'Archive');
});
}
}
}
doSelection(selection: any, buttonName: String) {
//remove after testing
let rowStr = "";
for (const row of selection) {
rowStr += row.rowid +",";
}
rowStr = rowStr.substring(0, rowStr.lastIndexOf(","));
const content = "Do you want to " +buttonName +" the " +selection.length +" rows selected?";
this.notificationService.smartMessageBox({
title : "<i class='fa fa-question-circle txt-color-yellow'></i> " +buttonName +" <span class='txt-color-white'><strong>" + $('#show-shortcut').text() + "</strong></span>",
content : content,
buttons : '[No][Yes]'
}, (ButtonPressed) => {
if (ButtonPressed === "Yes") {
//###console.log(buttonName +' selected rows');
//call appropriate web service
for(let i=0; i<selection.length; i++) {
//###console.log("row having database ID " +selection[i].rowid +" selected for " +buttonName);
}
}
});
}
getNotifGenMsgData() {
//###console.log("NotifGenMsgComponent getNotifGenMsgData - ENTRY");
const TESTING = false;
if(TESTING) {
//###console.log("NotifGenMsgComponent getNotifGenMsgData - ############# USING TEST DATA");
const resStr = '['
+ '{"checked":null,"rowid":"14","personID":"ALL","senderID":"ADMIN","message":"TEST DATA10 - TangleMyData has an outage planned for November 15, 2018 from 1:00 UTC until 2:00 UTC.","messageStatus":"NEW","messagePrimType":"SYSTEM","messageSubType":"GENERAL","dateExpires":"2018-11-15 09:02:37","dateCreated":"2018-11-05 09:02:37","dateLastUpdate":"2018-11-08 01:19:10"},'
+ '{"checked":null,"rowid":"15","personID":"ALL","senderID":"ADMIN","message":"TEST DATA11 - TangleMyData has an outage planned for November 15, 2018 from 1:00 UTC until 2:00 UTC.","messageStatus":"NEW","messagePrimType":"SYSTEM","messageSubType":"GENERAL","dateExpires":"2018-11-15 09:02:37","dateCreated":"2018-11-05 09:02:37","dateLastUpdate":"2018-11-08 01:19:10"},'
+ '{"checked":null,"rowid":"16","personID":"ALL","senderID":"ADMIN","message":"TEST DATA12 - TangleMyData has an outage planned for November 15, 2018 from 1:00 UTC until 2:00 UTC.","messageStatus":"NEW","messagePrimType":"SYSTEM","messageSubType":"GENERAL","dateExpires":"2018-11-15 09:02:37","dateCreated":"2018-11-05 09:02:37","dateLastUpdate":"2018-11-08 01:19:10"}'
+ ']';
this.genMsgs = JSON.parse(resStr);
} else {
this.notificationsService.getNotifGenMsgData().then(
(val) => {
this.genMsgs = this.notificationsService.genMsgs;
if (this.genMsgs) {
console.log("NotifGenMsgComponent getNotifGenMsgData - genMsgs is not null");
this.refreshDataTable();
} else {
//###console.log("NotifGenMsgComponent getNotifGenMsgData - genMsgs is null");
}
this.router.navigate(['/notifgenmsg']);
},
(err) => {
//###console.log("NotifGenMsgComponent getNotifGenMsgData - error: " +err);
}
);
}
//###console.log("NotifGenMsgComponent getNotifGenMsgData - EXIT");
}
refreshDataTable() {
if($(this.ngxDatatableComponent)) {
if($(this.ngxDatatableComponent).DataTable) {
console.log('refreshing ngxDataTable #####################');
const ngxDataTable = $($(this.ngxDatatableComponent).DataTable.tables()).DataTable();
ngxDataTable.clear().rows.add(this.genMsgs).draw();
}
}
}
}
Here's a screen shot of my General Messages table:
Thanks,
Bob
This question has an accepted answers - jump to answer
Answers
Hi @bobc02 ,
I'm not familiar with the framework, and really don't understand how those buttons are being initialised. For me, I've only seen custom buttons defined like this (at initialisation), or added later like this.
That said, if it's working with local data, it must be something to do with the async nature of the data loading - when the webservice loads it, there's going to be a delay, so it would be worth investigating that.
Sorry can't be any more use,
Cheers,
Colin
Hi Colin,
The standard way of defining the buttons, would probably work, but it would likely interfere with the plugin's datatable. The plugin provides me with some features that I'd prefer not to code myself. But, I appreciate the suggestion.
Yes, it is the async nature of the web service that is causing the problem. But, I was hoping the problem could be solved by some different DT calls, than the table.clear().rows.add(data_from_web_service).draw() operation I was using. But, clearly not.
I solved it by saving the first instance of the DT being created, as a property of the service.ts. I moved the button action listeners to the service.ts, as well. So, now when the data from the web service is returned, I do the table.clear().rows.add(data_from_web_service).draw() operation in the component.ts, as before, but the action listeners in the service.ts catches the button clicks.
Here's my modified component.ts:
Here's the important stuff in my service.ts:
Thanks,
Bob
Hi,
I was just going to have a look, but I'm getting:
That said, I see you say you've worked around it for now, so I guess the page might not show the error any more.
There are two things that spring to mind:
Allan
Hi Allan,
Ooops - I accidentally turned WAN IP verification on during testing this morning. Please try again.
I have actually solved the problem. I indicated that in my last comment. But, I do appreciate you having a look.
Thanks,
Bob
That's a good workaround. I'm not seeing anything obvious for why it wouldn't be working without the workaround I'm afraid. As you say its due to the async nature of it, but other than your workaround, I'm not certain what the best fix would be.
Allan