How can i edit contents of a <td> using angular-datatables? - angular-datatables

Table in a project is now implemented like this:
<table datatable="" dt-options="vm.dtOptions" dt-columns="vm.dtColumns" class="table table-custom"></table>
The code related to this table:
vm.dtColumns = [
DTColumnBuilder.newColumn('id', 'Login ID'),
DTColumnBuilder.newColumn('username', 'User Name'),
DTColumnBuilder.newColumn('email', 'Email'),
DTColumnBuilder.newColumn('usergrouproles', 'User Group Role'),
DTColumnBuilder.newColumn(null).withOption('defaultContent', '<button>button1</button><button>button2</button>').notSortable(),
DTColumnBuilder.newColumn(null).withOption('defaultContent', '<button>button3</button><button>button4</button><button>button5</button>').notSortable()
];
vm.dtOptions = DTOptionsBuilder
.newOptions()
.withBootstrap()
.withFnServerData(serverData)
.withDataProp('data')
.withOption('processing', true)
.withOption('serverSide', true)
.withOption('paging', true)
.withOption('rowCallback', function(row, data, index){
console.log("test rowCallback");
})
function serverData(sSource, aoData, fnCallback, oSettings) {
var draw = aoData[0].value;
var _order = aoData[2].value[0].dir.toUpperCase();
var _start = aoData[3].value;
var _end = _start + aoData[4].value;
var _sort = aoData[1].value[aoData[2].value[0].column].data;
UserSvc.getUsersPaginated(_start, _end, _order, _sort).then(function(result){
var records = {
'draw': draw,
'recordsTotal': result.length,
'recordsFiltered': result.totalCount,
'data': result
};
fnCallback(records);
});
}
For now, it seems okay except the User Group Role column - data there is in form of the object that is why I need to expand it there using ng-repeat. I'm aware of initComplete callback that I will be to apply finally but i cannot get how would I perform expand itself. I mean i want to operate in each cell but i have only an access to the whole row. I gave a try a renderWith() function in vm.dtColumns but it doesn't work at all. Could you show me the right direction?

Finally i found it. It's managed by createdCell option like .withOption('createdCell', withCreatedActionsCell).

Related

Saving user input from Popup in local storage not working properly

i have a marker with pop i was able to save user input from a form in my popup but the problem is it will only save if i have to click somewhere on the map first. heres my code...
L.marker([63.233627, 5.625])
.addTo(map)
.bindPopup('<form><select class="fodd" id="fodd-1"><option value="false">false</option><option
value="true">true</option></select><button type="button" id="btnInsert">Save</button></form>')
.on('click', foddStatus);
L.marker([72.181804, 45])
.addTo(map)
.bindPopup('<form><select class="fodd" id="fodd-2"><option value="false">false</option><option
value="true">true</option></select><button type="button" id="btnInsert">Save</button></form>')
.on('click', foddStatus);
function foddStatus(e) {
var btnInsert = document.getElementById("btnInsert");
btnInsert.onclick = function () {
// get user input when button is saved is clicked
var foddValue = document.querySelector('.fodd').value;
var foddLoc = document.querySelector('.fodd').id;
var midFodd = ":";
var var1 = foddLoc + midFodd;
var new_data = foddLoc + midFodd + foddValue;
console.log(new_data);
// if there is nothing saved on storage then save an empty array
if (localStorage.getItem('foddstatus') == null){
localStorage.setItem('foddstatus','[]');
}
// get old data and slap it to the new data
var old_data = JSON.parse(localStorage.getItem('foddstatus'));
old_data.push(new_data);
// save the old + new data to local storage
localStorage.setItem('foddstatus', JSON.stringify(old_data));
// console.log(key);
}
}
so what happens here on the first marker that I click the save button, it will save the values in localstorage, then when I go to the second marker and click the save button, it won't actually save on local storage. I have to click somewhere else on the map first in order to save the second marker's input on my localstorage.
this is a bit other approach to achive your goal, but maybe it helps.
This is only a test, without any validation etc. so please be aware of it!
I used here simple divs in the popups, inside an input and a button. Every button has its onclick attribute to call storeData function, which sets the localStorage key-value if the input is not empty. I used the input ids as keys.
The example snippet:
let ls = window.localStorage;
var map = L.map('map').setView([41, 21], 5);
var darkMap = L.tileLayer('https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png', {
maxZoom: 20,
attribution: '© Stadia Maps, © OpenMapTiles © OpenStreetMap contributors'
}).addTo(map);
var marker1 = L.marker([40, 10]).addTo(map);
var marker2 = L.marker([40, 30]).addTo(map);
marker1.bindPopup('<div><input class="ipt" id="ipt1" /><button onclick="storeData(this);" class="save">SAVE</button></div>');
marker2.bindPopup('<div><input class="ipt" id="ipt2" /><button onclick="storeData(this);" class="save">SAVE</button></div>');
function storeData(btn) {
let ipt = btn.parentNode.querySelector('.ipt');
if (ipt.value != '') {
ls.setItem(ipt.id, ipt.value);
let str = 'Data stored in localStorage with key: ' + ipt.id + ', value: ' + ls.getItem(ipt.id);
alert(str);
} else {
console.log('Empty input!');
}
}
And a working fiddle (Please open in non-incognito).

sap.m.table multi checkbox make it READ ONLY - On Condition + SAP UI5

This is my first post to Stack, appreciate the work you guys do, amazing.
I have a sap.m.table sap ui5 and i have 4 records
out of 4, 2 are selected by default, i want to disable the preselected once based on condition.
I have tried below code but its not working, any input please?
View
/results' }" **mode="MultiSelect"**
Controller logic
//--->disable the selected department checkboxes
var tbl = that.getView().byId('idImpactTable');
var header = tbl.$().find('thead');
var selectAllCb = header.find('.sapMCb');
selectAllCb.remove();
tbl.getItems().forEach(function(r) {
var obj = r.getBindingContext("impactModel").getObject();
var oStatus = obj.COMPLETED;
var cb = r.$().find('.sapMCb');
var oCb = sap.ui.getCore().byId(cb.attr('id'));
if (oStatus === "X") {
oCb.setSelected(true);
oCb.setEnabled(false);
} else {
oCb.setEnabled(false);
}
});
Multiselect Mode Table - Make selected check box read only
Last time I tried this I found it easiest to use the updateFinished event on the table, and then use an internal property of the column list item, like so:
onTableUpdateFinished: function (oEvent) {
oEvent.getSource().getItems().forEach(function (item) {
var data = item.getBindingContext().getObject();
item._oMultiSelectControl.setEnabled(!data.IsEnabled); //whatever your check is
});
}
You'll have to find a way to keep them disabled though when using the Select All checkbox at the top of the table. I ended up extending sap.m.Table to accomplish that, there might be easier ways...
My extension is like this
sap.ui.define([
"sap/m/Table"
], function(Control) {
return Control.extend("myapp.controls.MyTable", {
updateSelectAllCheckbox: function(oEvent) {
if (this._selectAllCheckBox && this.getMode() === "MultiSelect") {
var aItems = this.getItems();
var iSelectedItemCount = this.getSelectedItems().length;
var iSelectableItemCount = aItems.filter(function(oItem) {
//standard table does not check if the item is enabled
return oItem.getSelected() || oItem._oMultiSelectControl.getEnabled();
}).length;
// set state of the checkbox by comparing item length and selected item length
this._selectAllCheckBox.setSelected(aItems.length > 0 && iSelectedItemCount === iSelectableItemCount);
}
}
});
});
And just the standard renderer
sap.ui.define([
"sap/m/TableRenderer"
], function(Control) {
return Control.extend("myapp.controls.MyTableRenderer", {
});
});
I suppose I could have extended the ColumnListItem but that was more effort than I wanted to put into the table extension
I have managed to find the solution, please find sample code to achieve.
//--->disable the selected department checkboxes
var tbl = that.getView().byId("idImpactTable");
var header = tbl.$().find("thead");
var selectAllCb = header.find(".sapMCb");
selectAllCb.remove();
var aItems = that.byId("idImpactTable").getItems();
//---> Check individual item property value and select the item
aItems.forEach(function(oItem) {
debugger;
//---> If using OData Model items Binding, get the item object
var mObject = oItem.getBindingContext().getObject();
var sPath = oItem.getBindingContextPath();
var completed = oItem.oBindingContexts.impactModel.getProperty("COMPLETED");
//--->get the id of Multi Checkbox
var cb = oItem.$().find(".sapMCb");
var oCb = sap.ui.getCore().byId(cb.attr("id"));
if (completed === "X") {
oCb.setEditable(false);
oItem.setSelected(true);
oItem.getCells()[4].setEnabled(false);
} else {
oItem.setSelected(false);
}
});
Thank you,
Jacob.Kata
//--->disable the selected department checkboxes
var tbl = that.getView().byId('idImpactTable');
tbl.getItems().forEach(function(r) {
// this makes the trick --->
var oMultiSelCtrl = r.getMultiSelectControl();
oMultiSelCtrl.setDisplayOnly( true );
});

Dojo domConstruct - Inserting rows into a table

I'm working on an application that will allow people to select which data fields they would like a form to have. I had it working but when I tried to move the form fields into a table for a bit of visual structure I'm running into a problem.
// Now print the form to a new div
array.forEach(selectedFields, function(item, i) {
var l = domConstruct.create("label", {
innerHTML: item + ': ',
class: "dataFieldLabel",
for: item
});
var r = new TextBox({
class: "dataField",
name: item,
label: item,
title: item
});
var a = domConstruct.toDom("<tr><td>" + l + r + "</td></tr>");
domConstruct.place(a, "displayDataForm");
When I run the code I can select the fields I want but instead of textboxes being drawn on the screen text like:
[object HTMLLabelElement][Widget dijit.form.TextBox, dijit_form_TextBox_0]
[object HTMLLabelElement][Widget dijit.form.TextBox, dijit_form_TextBox_1]
Is printed to the screen instead. I think this is because I am passing domConstruct.place a mixture of text and objects. Any ideas about how to work around this? Thanks!
Try this :
require(["dojo/_base/array", "dojo/dom-construct", "dijit/form/TextBox", "dojo/domReady!"], function(array, domConstruct, TextBox){
var selectedFields = ["Foo", "Bar", "Baz"];
array.forEach(selectedFields, function(item, i) {
var tr = domConstruct.create("tr", {}, "displayDataForm"),
td = domConstruct.create("td", {}, tr),
l = domConstruct.create("label", {
innerHTML: item + ': ',
'class': 'dataFieldLabel',
'for': item
}, td, 'first'),
r = new TextBox({
'class': 'dataField',
name: item,
title: item
}).placeAt(td, 'last');
});
});
This assumes you have this in your html :
<table id="displayDataForm"></table>
Don't forget to quote "class" and "for" as these are part of javascript's grammar.
The domConstruct functions will not work with widgets. You can create the html and then query for the input node and create the test box.
var root = dom.byId("displayDataForm");
domConstruct.place(root,
lang.replace(
'<tr><td><label class="dataFieldLabel" for="{0}>{0}:</label><input class="inputNode"></input></td></tr>',
[item])
);
query('.inputNode', root).forEach(function(node){
var r = new TextBox({
'class': "dataField",
name: item,
label: item,
title: item
});
});
Craig thank you for all your help, you were right except that in the call to domConstruct.place the first argument is the node to append and the second argument is the refNode to append to. Thank you.
// Now print the form to a new div
array.forEach(selectedFields, function(item, i) {
var root = dom.byId("displayDataForm");
domConstruct.place(lang.replace(
'<tr><td><label class="dataFieldLabel" for="{0}">{0}: </label><input class="dataField"></input></td></tr>',
[item]), root
);
query('.dataField', root).forEach(function(node) {
var r = new TextBox({
'class': "dataField",
name: item,
label: item,
title: item
});
});
});

Handle selected event in autocomplete textbox using bootstrap Typeahead?

I want to run JavaScript function just after user select a value using autocomplete textbox bootstrap Typeahead.
I'm searching for something like selected event.
$('.typeahead').on('typeahead:selected', function(evt, item) {
// do what you want with the item here
})
$('.typeahead').typeahead({
updater: function(item) {
// do what you want with the item here
return item;
}
})
For an explanation of the way typeahead works for what you want to do here, taking the following code example:
HTML input field:
<input type="text" id="my-input-field" value="" />
JavaScript code block:
$('#my-input-field').typeahead({
source: function (query, process) {
return $.get('json-page.json', { query: query }, function (data) {
return process(data.options);
});
},
updater: function(item) {
myOwnFunction(item);
var $fld = $('#my-input-field');
return item;
}
})
Explanation:
Your input field is set as a typeahead field with the first line: $('#my-input-field').typeahead(
When text is entered, it fires the source: option to fetch the JSON list and display it to the user.
If a user clicks an item (or selects it with the cursor keys and enter), it then runs the updater: option. Note that it hasn't yet updated the text field with the selected value.
You can grab the selected item using the item variable and do what you want with it, e.g. myOwnFunction(item).
I've included an example of creating a reference to the input field itself $fld, in case you want to do something with it. Note that you can't reference the field using $(this).
You must then include the line return item; within the updater: option so the input field is actually updated with the item variable.
first time i've posted an answer on here (plenty of times I've found an answer here though), so here's my contribution, hope it helps. You should be able to detect a change - try this:
function bob(result) {
alert('hi bob, you typed: '+ result);
}
$('#myTypeAhead').change(function(){
var result = $(this).val()
//call your function here
bob(result);
});
According to their documentation, the proper way of handling selected event is by using this event handler:
$('#selector').on('typeahead:select', function(evt, item) {
console.log(evt)
console.log(item)
// Your Code Here
})
What worked for me is below:
$('#someinput').typeahead({
source: ['test1', 'test2'],
afterSelect: function (item) {
// do what is needed with item
//and then, for example ,focus on some other control
$("#someelementID").focus();
}
});
I created an extension that includes that feature.
https://github.com/tcrosen/twitter-bootstrap-typeahead
source: function (query, process) {
return $.get(
url,
{ query: query },
function (data) {
limit: 10,
data = $.parseJSON(data);
return process(data);
}
);
},
afterSelect: function(item) {
$("#divId").val(item.id);
$("#divId").val(item.name);
}
Fully working example with some tricks. Assuming you are searching for trademarks and you want to get the selected trademark Id.
In your view MVC,
#Html.TextBoxFor(model => model.TrademarkName, new { id = "txtTrademarkName", #class = "form-control",
autocomplete = "off", dataprovide = "typeahead" })
#Html.HiddenFor(model => model.TrademarkId, new { id = "hdnTrademarkId" })
Html
<input type="text" id="txtTrademarkName" autocomplete="off" dataprovide="typeahead" class="form-control" value="" maxlength="100" />
<input type="hidden" id="hdnTrademarkId" />
In your JQuery,
$(document).ready(function () {
var trademarksHashMap = {};
var lastTrademarkNameChosen = "";
$("#txtTrademarkName").typeahead({
source: function (queryValue, process) {
// Although you receive queryValue,
// but the value is not accurate in case of cutting (Ctrl + X) the text from the text box.
// So, get the value from the input itself.
queryValue = $("#txtTrademarkName").val();
queryValue = queryValue.trim();// Trim to ignore spaces.
// If no text is entered, set the hidden value of TrademarkId to null and return.
if (queryValue.length === 0) {
$("#hdnTrademarkId").val(null);
return 0;
}
// If the entered text is the last chosen text, no need to search again.
if (lastTrademarkNameChosen === queryValue) {
return 0;
}
// Set the trademarkId to null as the entered text, doesn't match anything.
$("#hdnTrademarkId").val(null);
var url = "/areaname/controllername/SearchTrademarks";
var params = { trademarkName: queryValue };
// Your get method should return a limited set (for example: 10 records) that starts with {{queryValue}}.
// Return a list (of length 10) of object {id, text}.
return $.get(url, params, function (data) {
// Keeps the current displayed items in popup.
var trademarks = [];
// Loop through and push to the array.
$.each(data, function (i, item) {
var itemToDisplay = item.text;
trademarksHashMap[itemToDisplay] = item;
trademarks.push(itemToDisplay);
});
// Process the details and the popup will be shown with the limited set of data returned.
process(trademarks);
});
},
updater: function (itemToDisplay) {
// The user selectes a value using the mouse, now get the trademark id by the selected text.
var selectedTrademarkId = parseInt(trademarksHashMap[itemToDisplay].value);
$("#hdnTrademarkId").val(selectedTrademarkId);
// Save the last chosen text to prevent searching if the text not changed.
lastTrademarkNameChosen = itemToDisplay;
// return the text to be displayed inside the textbox.
return itemToDisplay;
}
});
});

Drag from Tree to div

I am trying to implement a drag and drop senario from an extJs TreePanel into a div in the body of the page. I have been following an example by Saki here.
So far I have the below code:
var contentAreas = new Array();
var tree = new Ext.tree.TreePanel({
title : 'Widgets',
useArrows: true,
autoScroll: true,
animate: true,
enableDrag: true,
border: false,
layout:'fit',
ddGroup:'t2div',
loader:new Ext.tree.TreeLoader(),
root:new Ext.tree.AsyncTreeNode({
expanded:true,
leaf:false,
text:'Tree Root',
children:children
}),
listeners:{
startdrag:function() {
$('.content-area').css("outline", "5px solid #FFE767");
},
enddrag:function() {
$('.content-area').css("outline", "0");
}
}
});
var areaDivs = Ext.select('.content-area', true);
Ext.each(areaDivs, function(el) {
var dd = new Ext.dd.DropTarget(el, {
ddGroup:'t2div',
notifyDrop:function(ddt, e, node) {
alert('Drop');
return true;
}
});
contentAreas[contentAreas.length] = dd;
});
The drag begins and the div highlights but when I get over the div it does not show as a valid drop target and the drop fails.
This is my first foray into extJS. I'm JQuery through and through and I am struggling at the moment.
Any help would be appreciated.
Ian
Edit
Furthermore if I create a panel with a drop target in it, this works fine. What is the difference between creating an element and selecting an existing element from the dom. This is obviously where I am going wrong but I'm none the wiser. I have to be able to select existing dom elements and make them into drop targets so the code below is not an option.
Here is the drop target that works
var target = new Ext.Panel({
renderTo: document.body
,layout:'fit'
,id:'target'
,bodyStyle:'font-size:13px'
,title:'Drop Target'
,html:'<div class="drop-target" '
+'style="border:1px silver solid;margin:20px;padding:8px;height:140px">'
+'Drop a node here. I\'m the DropTarget.</div>'
// setup drop target after we're rendered
,afterRender:function() {
Ext.Panel.prototype.afterRender.apply(this, arguments);
this.dropTarget = this.body.child('div.drop-target');
var dd = new Ext.dd.DropTarget(this.dropTarget, {
// must be same as for tree
ddGroup:'t2div'
// what to do when user drops a node here
,notifyDrop:function(dd, e, node) {
alert('drop');
return true;
} // eo function notifyDrop
});
}
});
See if adding true as the second param here makes any difference:
var areaDivs = Ext.select('.content-area', true);
As a cosmetic note, the param name e conventionally indicates an event object (as in the second arg of notifyDrop). For an element, el is more typical. Doesn't matter functionally, but looks weird to someone used to Ext code to see e passed into the DropTarget constructor.
If you are having problem duplicating a working example such as that, copy the entire thing, then modify it to your needs line-by-line - you can't go wrong.
As i know you can't set DropZone to any Ext element, just to Ext component. So this might be you problem. Try to use DropTarget instead of DropZone.