how to continue d3 chain within embedded switch? - d3.js

.append(function(d,i) {
switch (tabData.list[tabNo].type) {
case 'actl':
// return a div() chain .attr/.property/.on
var v = document.createElement("div");
var v1 = d3.select(v)
.append("h3")
.html("HFree");
return v1;
//return document.createElement("div");
break;
case 'fc':
// return a div() chain .attr/.property/.on
return document.createElement("div");
break;
case 't':
// return a div().attr/.property/.on
return document.createElement("div");
break;
}
})
.append() takes either a string 'div or function that returns created element. How do I continue the chain within the switch as in // return a div() chain .attr/.property/.on? I have edited the first case statement to one of the things I tried that does not work in order to explain better.

Related

How to display and hide columns based on the two dropdown selection using ag grid

Basically, I have two dropdowns a and b.
Based on the combination of these two dropdowns Ineed to hide / show colums using ag grid.
Eg: if I choose 'xyz' in dropdown a and '123' in dropdown b, 2 columns wiil be displayed. Similarly if choose dropdown 'ghj' and '456' in dropdown b, some ther 3 columns will be selected and the first 2 columns will be no longer be visible / available.
I can use if else conditionsbut I need to check for all the possible combinations. Is there an easy way to do so?
dropdown a
onReportingType(e) {
// console.log(e);
this.reportData = e;
this.reportSelArr.push(this.reportData);
console.log(this.reportSelArr);
}
dropdown b
onDataPoint(e) {
console.log(e);
this.dataPointData = e;
this.dataPointSelArr.push(this.dataPointData);
console.log(this.dataPointSelArr);
this.addRatingCol();
}
Condition applied for now
addRatingCol() {
// console.log(this.reportSelArr);
// console.log(this.dataPointSelArr);
for (let i = 0; i < this.reportSelArr.length; i++) {
for (let j = 0; j < this.dataPointSelArr.length; j++) {
if (this.reportSelArr[i].reportingTypeName === 'Outstanding') {
if (this.dataPointSelArr[j].dataPointName === 'Rating') {
this.gridColumnApi.setColumnsVisible(['newRatingName', 'newRatingReleaseDate'], true);
return true;
} else if (this.dataPointSelArr[j].dataPointName === 'Rating Outlook') {
this.gridColumnApi.setColumnsVisible(['newOutlookName', 'newOutlookDate', 'outlookEndDate'], true);
} else if (this.dataPointSelArr[j].dataPointName === 'Rating Watch') {
this.gridColumnApi.setColumnsVisible(['newRatingWatchName', 'newRatingWatchDate', 'ratingwatchEndDate'], true);
}
}
} // end of the for loop
}
if (this.addCol === true && this.addReport === true){
this.gridColumnApi.setColumnsVisible(['newRatingName', 'newRatingReleaseDate'], true);
} else {
this.gridColumnApi.setColumnsVisible(['newRatingName', 'newRatingReleaseDate'], false);
}
}
If you are using ES6..
Instead of the 2 for loops i would prefer using filter for the first loop and finding whether it has the reporting type as outstanding.
const outstanding = this.reportSelArr.filter(elem => elem.reportingTypeName === 'Outstanding')
i would then use the return value of the filter to determine whether or not to run the second for loop which can be through a map.
if (outstanding) {
this.dataPointSelArr.map(elem => {
const { dataPointName } = elem
switch(dataPointName) {
case 'Rating': {
//statements;
break;
}
case 'Rating Outlook': {
//statements;
break;
}
case 'Rating Watch':{
//statements;
break;
}
default: {
//statements;
break;
}
}
})
}

For loop in promise function

I have below functions that I am trying to use an async function to check if an item Id was already added into a grid. But, I am stuck at the for loop "processFindCode" function, it always returns false. How to make the checking routine work and continue to addItem function?
My objective,
1. a loop up event pass in selected array values
2. get needed info array via web api
3. process each of array item
4. validate if the item.Id_item_code already exists in detail grid, if not add a new item into the grid
sorry for the lengthy code, I am considered new to js. please also advise the best way to achieve my objective.
Thank in advance
var theList = this.value;
if (theList == "") {
return true;
}
// Set up aysnc promise function
async function processAPIResult() {
let result;
let promises = []; //setup a promises aray
// Loop thru Lookup selections
// results store in the promises aray
theList.split(',').forEach(function (kId, k) {
promises.push(make_api_call(kId));
})
result = await Promise.all(promises); // async await
return result;
}
// Call API Function
function make_api_call(id) {
return ($.get(ew.API_URL + "GetQuotationDetail/" + encodeURIComponent(id)));
}
function delay() {
return new Promise(resolve => setTimeout(resolve, 300));
}
async function addItem(kcode) {
var ridx = $("#key_count_fs_invoicedtlgrid")[0].value; // get actual table row
// Get serices information from API
var tQty = 1;
if (ridx == 1 && $("#x1_Id_item_code")[0].value == "") {
$("#x" + ridx + "_Id_item_code").value(kcode);
$("#x" + ridx + "_qty").value(tQty);
$("#x" + ridx + "_Id_item_code").select();
$("#x" + ridx + "_Id_item_code").change();
//$("#x" + ridx + "_Id_quotattoindetl").value(Id_quotationDetail); // store quotation detail Id
} else {
// 2nd row onward
// when it is available but it it is not empty, create a new row
if (typeof $("#x" + ridx + "_Id_item_code") === 'undefined' || $("#x" + ridx + "_Id_item_code")[0] != "") {
ew.addGridRow('#tbl_s_invoicedtlgrid');
}
ridx = $("#key_count_fs_invoicedtlgrid")[0].value;
var c_part_code = $("#x" + ridx + "_Id_item_code")[0];
var c_qty = $("#x" + ridx + "_qty")[0];
c_part_code.value = kcode;
c_qty.value = fmtDecimal(tQty, 'qty');
$("#x" + ridx + "_Id_item_code").select();
$("#x" + ridx + "_Id_item_code").change();
//$("#x" + ridx + "_Id_quotattoindetl").value(Id_quotationDetail); // store quotation detail Id
// trigger onChange to updateAmount() function;
$("#x" + ridx + "_qty").change();
}
}
async function processFindCode(code) {
found = false;
var rCnt = $("#key_count_fs_invoicedtlgrid")[0].value;
for (j = 1; j < rCnt + 1; j++) {
// loop thru row and col
if ($("#x" + j + "_item_code").val() != null) {
if ($("#x" + j + "_item_code").val() == kcode) {
if ($("#x" + j + "_item_code")[0].style.display != "none") { // visible row only. Deleted row's display is set to hidden.
found = true;
}
break; // exit loop column
}
}
if (found) {
break; // exit loop row
}
} // end for loop rCnt
isFound = found;
return isFound;
}
async function processItemCode(code) {
// notice that we can await a function
// that returns a promise
let isFound = await processFindCode(code);
await delay();
if (!isFound) {
await addItem(code);
}
console.log('Done! ' + code);
//await delay();
//console.log(item.Id_item_code);
}
async function processAPIitem(item) {
for (const itm of item) {
await processItemCode(itm.Id_item_code);
}
//console.log('Done! '+ apiitem.Id_item_code);
}
// main async task to get results
//-------------------------------
async function doTask() {
//get result form API function
let result = await processAPIResult();
//process each API array
for (const item of result) {
await processAPIitem([item]);
}
}
doTask();
Simple answer: $item_code.hide() hides; it isn't a test. Use $item_code.is(':visible') instead.
function processFindCode(code) {
var found = false;
var rCnt = $('#key_count_fs_invoicedtlgrid').val();
for (var j=1; j<rCnt+1; j++) {
if ($('#x' + j + '_item_code').val() != null) {
if ($('#x' + j + '_item_code').val() == code) {
if ($('#x' + j + '_item_code').is(':visible')) {
found = true;
break;
}
}
}
}
return found;
}
Longer answer: Finding the desired element with $('#x' + j + '_item_code') is inefficient especially when performed three times. You can improve matters by leveraging the power of javascript/jQuery and write something like this.
function processFindCode(code) {
var $rows = $('#tbl_s_invoicedtlgrid tbody tr'); // select all table rows in the table's tbody (assumed selector) .
return $rows.get().reduce(function(bool, row) {
return bool || $("id*='_item_code'", row).filter(':visible').filter(function() {
return this.value === code;
}).length > 0;
}, false);
}
This is still not as efficient as it could be. The "id*='_item_code'" selector is pretty nasty but at least it only applies to one row at a time, not the whole DOM.
For vastly improved efficiency, give the item_code element class="item_code" and select with $(".item_code", row). The addItem() function would benefit greatly from the same approach.

Keyboard input using socket.io

At the moment I have been able to get the sprite to move using the mouse but I am stuck on getting it to move using the keyboard
Client code shortened:
var Client = {};
Client.socket = io.connect();
Client.sendClick = function(x,y){
Client.socket.emit('click',{x:x,y:y});
};
Client.socket.on('move',function(data){
Game.movePlayer(data.id,data.x,data.y);
});
Server code shortened:
socket.on('click',function(data){
console.log('click to '+data.x+', '+data.y);
socket.player.x = data.x;
socket.player.y = data.y;
io.emit('move',socket.player);
});
I've tried something along these lines
Client.sendKey = function(data){
switch(data.keyCode)
{
case 40:
Client.socket.emit('movement', data.y - 10);
break;
case 38:
Client.socket.emit('movement', data.y + 10);
break;
case 37:
Client.socket.emit('movement', data.x - 10);
break;
case 39:
Client.socket.emit('movement', data.x + 10);
break;
}
});
This would be an example of how to handle keycodes within a game loop scenario and could also be malleable if you are not using this as part of a game. I'm also presuming your using JavaScript, though if I'm wrong I'll remove this answer.
//keys array
var keys = [];
//Bind document event listeners
document.addEventListener('keyup', keyUp);
document.addEventListener('keydown', keyDown);
function moveClient(KeyCodeArr) {
//if a key code is true then it means the key has been pressed.
if (KeyCodeArr[40]) {
Client.socket.emit('movement', data.y - 10);
}
if (KeyCodeArr[38]) {
Client.socket.emit('movement', data.y + 10);
}
if (KeyCodeArr[37]) {
Client.socket.emit('movement', data.x - 10);
}
if (KeyCodeArr[39]) {
Client.socket.emit('movement', data.x + 10);
}
}
/**
* These two events handle
*/
//key down event for use with listener
function keyDown(event) {
keys[event.keyCode] = true;
}
//key up event for use with event listener
function keyUp(event) {
keys[event.keyCode] = false;
}
//main in this example would be a game loop.
function main() {
moveClient();
}

Set the color in a choropleth based on the key

I'm trying to set the color of a choropleth based on some properties linked to the key.
However, all the methods to set the color only have the value of that specific place, but not its key.
var map = dc.geoChoroplethChart(dom)
.height(width*0.8)
.width(width)
.dimension(dim)
.projection(projection)
.colorAccessor(function(d,i){
// it isn't the usual d={key,value} but only d=value
})
.colorCalculator(function(d,i){
// it isn't the usual d={key,value} but only d=value
//and it's deprecated
})
.title(function (d) {return d.key + ': ' + d.value;})
// got the key,value as expected
how do I get the key from colorAccessor? it works fine from the other functions (eg title)
so it turns out it's "normal". As suggested by Gordon, the solution is to map the index of the geojson with the data you want. In my case, I have extra data about each countries on a country array:
var geojson=topojson.feature(europe,europe.objects.countries);
// map index in the map to country data this hack is to solve a problem of not having the key on the colorAccessor
var geo2data=[];
geojson.features.forEach(function(d,i1){
var i2=country.findIndex(function(c) {
return c.country.toUpperCase()==d.id});
geo2data[i1] = i2;
});
var map = dc.geoChoroplethChart(dom)
...
.colorAccessor(function(v,i){
if (geo2data[i] >= 0){
//geo2data[i] contains extra values, eg
return v / country[geo2data[i]].threshold;
}
return v;
})
The workaround I ended up using:
create a custom reduce function that duplicates the key in the value.
//the iso code of the country is the key
var group = dim.group().reduce(
function (p, v) {
p.total += +v.total;
if (p.iso == "") {
p.iso = v.country;
}
return p;
},
function (p, v) {
p.total -= +v.total;
return p;
},
function () { return {
total:0,iso:""
};
});
var map = dc.geoChoroplethChart(dom)
.colorAccessor(function(d){
if (!d || !d.value.iso)
return null; // area without data
// now d.value.iso contains the key, and d.value.total contains the value
return colorIndex(d.value.iso,d.value.total);// do magic
})
....

How should I be using the Kentico TreeNode.Update method?

I am trying to run the attached code to update some data for a particular document type but it is not actually updating anything.
My currentDocumentNodeId() method is pulling back a NodeId based on some other criteria and then each of these Nodes that it is getting is of the type HG.DocumentLibraryItem which have the columns IsPublic, IsRepMining, IsRepPower, IsRepProcess, and IsRepFlexStream. But when I call the update method and then pull back those Columns in the SQL table for this Custom Document Type, the values are all Null. Each of those columns in the HG.DocumentLibraryItem document type are set to boolean I have tried using the Node.SetValue() method and setting it to true and 1; neither way works to update that column.
Any ideas what I am doing wrong? Am I doing the call correctly?
See my code below:
public static void GetDocumentAreaAssignments()
{
var cmd = new SqlCommand
{
CommandText ="This is pulling back 2 rows, one with Id and one with Text",
CommandType = CommandType.Text,
Connection = OldDbConnection
};
OldDbConnection.Open();
try
{
using (SqlDataReader rdr = cmd.ExecuteReader())
{
var count = 0;
while (rdr.Read())
{
try
{
var documentId = TryGetValue(rdr, 0, 0);
var areaAssignment = TryGetValue(rdr, 1, "");
var currentDocumentNodeId = GetNodeIdForOldDocumentId(documentId);
var node = currentDocumentNodeId == 0
? null
: Provider.SelectSingleNode(currentDocumentNodeId);
if (node != null)
{
switch (areaAssignment.ToLower())
{
case "rep mining":
node.SetValue("IsRepMining", 1);
break;
case "rep power":
node.SetValue("IsRepPower", 1);
break;
case "rep process":
node.SetValue("IsRepProcess", 1);
break;
case "rep flexStream":
node.SetValue("IsFlexStream", 1);
break;
case "public":
node.SetValue("IsPublic", 1);
break;
}
node.Update();
Console.WriteLine("Changed Areas for Node {0}; item {1} complete", node.NodeID,
count + 1);
}
}
catch (Exception ex)
{
}
count++;
}
}
}
catch (Exception)
{
}
OldDbConnection.Close();
}
The coupled data (as IsRepMining field) are only updated when you retrieve a node that contains them. To do that you have to use overload of the SelectSingleNode() method with a className parameter. However I'd recommend you to always use the DocumentHelper to retrieve documents. (It will ensure you work with the latest version of a document...in case of workflows etc.)
TreeProviderInstance.SelectSingleNode(1, "en-US", "HG.DocumentLibraryItem")
DocumentHelper.GetDocument(...)
DocumentHelper.GetDocuments(...)

Resources