0

I am working on displaying the Json output of a generated flowchart. I have stored the dropped elements' details in an array called finalArray and am simply adding it to the Json display. All the details seem to be properly displayed except for the attribute names and their attribute types that are retrieved from another array.

I've commented the part that doesn't work in the following code segment

Code in Context

function saveFlowchart(){
    var nodes = [];
    var matches = [];
    var searchEles = document.getElementById("container").children;
    for(var i = 0; i < searchEles.length; i++) 
    {
        matches.push(searchEles[i]);
        var idOfEl = searchEles[i].id;

        if(searchEles[i].id !=null || searchEles[i].id !="")
        {
            var $element = $("#" + searchEles[i].id);
            var dropElem = $("#" + searchEles[i].id).attr('class');

            var position = $element.position();
            position.bottom = position.top + $element.height();
            position.right = position.left + $element.width();
            //alert("class:"+dropElem+"\nTop position: " + position.top + "\nLeft position: " + position.left + "\nBottom position: " + position.bottom + "\nRight position: " + position.right);

            finalArray[i] = [];

            finalArray[idOfEl-1][0]= idOfEl;
            finalArray[idOfEl-1][1]= dropElem;
            finalArray[idOfEl-1][2]= [];
            finalArray[idOfEl-1][2][0] = position.top;
            finalArray[idOfEl-1][2][1] = position.left;
            finalArray[idOfEl-1][2][2] = position.bottom;
            finalArray[idOfEl-1][2][3] = position.right;

            var elId = parseInt(idOfEl);

            if (dropElem=="streamdrop ui-draggable")
            {
                for(var count=0;count<100;count++)
                {
                    if(createdImportStreamArray[count][0]==idOfEl)
                    {
                        finalArray[elId-1][3]=  createdImportStreamArray[count][1]; //Selected Stream from Predefined Streams
                        finalArray[elId-1][4]= createdImportStreamArray[count][2]; //asName
                        //alert("createdImportStreamArray[count][0]==elId\n"+count);
                    }
                    else if(createdExportStreamArray[count][0]==idOfEl)
                    {
                        finalArray[elId-1][3]= createdExportStreamArray[count][1]; //Selected Stream from Predefined Streams
                        finalArray[elId-1][4]= createdExportStreamArray[count][2]; //asName
                    }
                    else if(createdDefinedStreamArray[count][0]==idOfEl)
                    {
                        finalArray[elId-1][3]= createdDefinedStreamArray[count][1]; //Stream Name
                        finalArray[elId-1][4]= createdDefinedStreamArray[count][4]; //Number of Attributes
                        finalArray[elId-1][5]=[];
                        for(var f=0;f<createdDefinedStreamArray[count][4].length;f++)
                        {
                            finalArray[elId-1][5][f]=[];

The following two are not displayed individually. Instead only "[]" is shown

                            finalArray[elId-1][5][f][0]=createdDefinedStreamArray[count][2][f][0]; //Attribute Name
                            finalArray[elId-1][5][f][1]=createdDefinedStreamArray[count][2][f][1]; // Attribute Type
                        }
                    }
                }
            }


            else if (dropElem=="wstream ui-draggable")
            {
                finalArray[elId-1][3]= createdWindowStreamArray[elId-1][1]; // Window Name
                finalArray[elId-1][4]= createdImportStreamArray[elId-1][2]; //Selected Stream Index
                finalArray[elId-1][4]= createdImportStreamArray[elId-1][3]; //Selected Stream
                finalArray[elId-1][5]= [];
                var AttributeNumber = createdWindowStreamArray[elId-1][4].length;
                for(var attrFill=0;attrFill<AttributeNumber;attrFill++)
                {
                    finalArray[elId-1][5][attrFill]=[];
                    finalArray[elId-1][5][attrFill][0]=createdWindowStreamArray[elId-1][4][attrFill][0];
                    finalArray[elId-1][5][attrFill][1]=createdWindowStreamArray[elId-1][4][attrFill][1];
                }
                //alert("createdImportStreamArray[count][0]==elId\n"+count);
            }

            else if (dropElem=="squery ui-draggable")
            {
                ElementType="squery";
            }

            else if (dropElem=="wquery ui-draggable")
            {
                ElementType="wquery";
            }

            else if (dropElem=="joquery ui-draggable")
            {
                ElementType="joquery";
            }

            else if(dropElem=="stquery ui-draggable")
            {
                ElementType="stquery";
            }

            else if(dropElem=="partitiondrop ui-draggable")
            {
                ElementType="partitiondrop";
            }
        }

    }

    alert(finalArray);

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    $(".node").each(function (idx, elem) {
        var $elem = $(elem);
        var endpoints = jsPlumb.getEndpoints($elem.attr('id'));
        console.log('endpoints of '+$elem.attr('id'));
        console.log(endpoints);
        nodes.push({
            blockId: $elem.attr('id'),
            nodetype: $elem.attr('data-nodetype'),
            positionX: parseInt($elem.css("left"), 10),
            positionY: parseInt($elem.css("top"), 10)
        });
    });
    var connections = [];
    $.each(jsPlumb.getConnections(), function (idx, connection) {
        connections.push({
            connectionId: connection.id,
            pageSourceId: connection.sourceId,
            pageTargetId: connection.targetId
        });
    });

    var flowChart = {};
    flowChart.nodes = nodes;
    flowChart.connections = connections;
    flowChart.elements =finalArray;
    flowChart.numberOfElements = finalArray.length;

    var flowChartJson = JSON.stringify(flowChart);
    //console.log(flowChartJson);

    $('#jsonOutput').val(flowChartJson);
}

Current Json Output

Basic Interface

createdDefinedStream Array

//Array that stores all Defined stream data
var createdDefinedStreamArray = [];
for(var x = 0; x < 100; x++){
    createdDefinedStreamArray[x] = [];
    for(var y = 0; y < 5; y++){
        createdDefinedStreamArray[x][y] = null
    }
}

 function storeDefinedStreamInfo(newAgent,i,e,kind)
{
    var StrName= document.getElementById("StreamNameInput").value;
    var StreamElementID = i;
    var table = document.getElementById('attrtable');
    var tblerows = (table.rows.length);
    createdDefinedStreamArray[i][2]=new Array(tblerows);


    for (r = 1; r < tblerows; r++) {
        for(var c=0; c<1;c++) {
            var attrNm = table.rows[r].cells[c].innerHTML;
            var attrTp = table.rows[r].cells[1].innerHTML;
            createdDefinedStreamArray[i][2][r-1]= new Array(2);
            createdDefinedStreamArray[i][2][r-1][0]=attrNm;
            createdDefinedStreamArray[i][2][r-1][1]=attrTp;
        }

    }

    createdDefinedStreamArray[i][0]=StreamElementID;
    createdDefinedStreamArray[i][1]=StrName;
    createdDefinedStreamArray[i][3]="Defined Stream";
    createdDefinedStreamArray[i][4]= tblerows;



    var prop = $('<a onclick="doclickDefine(this)"><b><img src="../Images/settings.png" class="settingsIconLoc"></b></a> ').attr('id', (i+'-prop'));
    var conIcon = $('<img src="../Images/connection.png" onclick="connectionShowHideToggle(this)" class="showIconDefined"></b></a> ').attr('id', (i+'vis'));
    newAgent.text(StrName).append('<a class="boxclose" id="boxclose"><b><img src="../Images/Cancel.png"></b></a> ').append(conIcon).append(prop);
    dropCompleteElement(newAgent,i,e,kind);
}
  • Could you please provide a small sample of the HTML chart? Mainly to see the relation between each searchEles[i] and the $element and dropelement they contain. – Shilly Sep 06 '16 at 09:20
  • @Shilly I've included the interface. This is a simple container onto which the toobox elements can be dragged and dropped onto. Later the `searchEles` will gather all dropped elements and create the json –  Sep 06 '16 at 09:25
  • I'm still cleaning up a bit, since it's complicated counting all those arrays. Have you thoguht about using objects instead of arrays, it'd make the structure way easier to follow. Anyways, I meant the actual html code, but doesn't matter. – Shilly Sep 06 '16 at 09:44

1 Answers1

0

Could you please try running this code on your data to see if I missed anything and if the problem is solved? I replaced all of the loops with maps, so it's a little bit clearer which data gets selected where.

function saveFlowchart(){
    var nodes = [],
        searchElements = Array.prototype.slice.call(document.querySelector('#container').childNodes),
        matches = searchElements.slice(),
        finalArray,
        ElementType, // this was global in the example and is currently not used in the sample code.
        map = function map( ary, field ) {
            return ary.reduce(function( map, element ) {
                map[element[field]] = element;
                return map;
            }, {});
        },
        // Let's create a bunch of maps so we can reference each id directly instead of having to loop Each array for each element several times.
        // This results in easier to understand code and runs faster, since nested arrays several levels deep can cause confusion.
        // Noted the signature of each provided array.
        // importStreamMap: [ id, selected stream, asName ]
        importStreamMap = map(createdImportStreamArray, 0),
        // exportStreamMap: [ id, selected stream, asName ]
        exportStreamMap = map(createdExportStreamArray, 0),
        // definedStreamMap: [ id, stream name, [ [attr1 name, attr1 type], [attr2 name, attr2 type], ... ], ???, attr count ]
        definedStreamMap = map(createdDefinedStreamArray, 0),
        // windowStreamMap: [ id, window name, selected stream index, selected stream (name?) ]
        windowStreamMap = map(createdWindowStreamArray, 0),
        classHandlers = {
            'streamdrop ui-draggable' : function( id, result ) {
                if (importStreamMap.hasOwnProperty(id)) {
                    result.push(importStreamMap[id][1]); // selected stream
                    result.push(importStreamMap[id][2]); // asName
                }
                else if (exportStreamMap.hasOwnProperty(id)) {
                    result.push(exportStreamMap[id][1]); // selected stream
                    result.push(exportStreamMap[id][2]); // asName                  
                }
                else if (definedStreamMap.hasOwnProperty(id)) {
                    result.push(definedStreamMap[id][1]); // stream name
                    result.push(definedStreamMap[id][4]); // attr count
                    result.push(definedStreamMap[id][2].slice()); // just clone the entire array of key/value pairs, no need to recreate it since they are strings.
                }
            },
            'wstream ui-draggable' :  function( id, result ) {
                result.push(windowStreamMap[id][1]); // window name
                // one of these two is obsolete, since the second overwrites the first. Selected stream according to the array signature ???? 
                // result.push(importStreamMap[id][2]);
                result.push(importStreamMap[id][3]);
                result.push(windowStreamMap[id][4].slice()); // clone the array again.
            },
            'wquery ui-draggable' : function( id, result ) {
                ElementType = 'wquery';
            },
            'joquery ui-draggable' : function( id, result ) {
                ElementType = 'joquery';
            },
            'stquery ui-draggable' : function( id, result ) {
                ElementType = 'stquery';
            },
            'partitiondrop ui-draggable' : function( id, result ) {
                ElementType = 'partitiondrop';
            }
        };
    finalArray = searchElements.reduce(function( ary, element ) {
        var id = parseInt(element.id, 10),
            $element,
            dropCls,
            position,
            result;
        if (id) {
            $element = element.querySelector('#' + id);
            dropCls = $element.className;
            position = $element.position();
            position.bottom = position.top + $element.height();
            position.right = position.left + $element.width();
            result = [ id, dropCls, [ position.top, position.left, position.bottom, position.right ] ];
            classHandlers[dropCls](id, result);
            ary.push(result);
        }
        return ary;
    }, []);
    ////////////////////////////////////////////////////////////////////
    // Rest of the code stays the same. If the attributes aren't showing up yet, check if the array is correct and if the indexes are ok.
    // From the array signatures, we get that the createdDefinedStreamArray contains the attributes instead of the createdWindowStreamArray.
    // For the record, it'd be easier to just use key-value pairs and objects in the JSON, if the API allows that.
}
Shilly
  • 8,511
  • 1
  • 18
  • 24
  • Hi, Thanks a million for the trouble you went through. I tried executing this an am getting a trivial error saying **Uncaught SyntaxError: Failed to execute 'querySelector' on 'Element': '#1' is not a valid selector.** –  Sep 06 '16 at 10:47
  • According to [this](http://stackoverflow.com/questions/37270787/uncaught-syntaxerror-failed-to-execute-queryselector-on-document) digits can be utilized as ids as long as they are unique hence am unable to figure out what went wrong here. –  Sep 06 '16 at 10:49
  • Hence I asked the relationship between the $element and the container it's in, since I didn't completely understand if it's a direct child node or somewhere deeper in the html tree. So it'll have to be `document.querySelector` instead of `element.querySelector`. I wrongly assumed it was a childnode. – Shilly Sep 06 '16 at 11:18
  • I'm sorry, without more info I don't think my post is usable then. Have you checked if the second field of each record in createdDefinedSTreamArray actually contains those attribute keys and values? – Shilly Sep 06 '16 at 11:39
  • I changed the code segments to this-> `$element = $("#"+id); dropCls = $("#"+id).attr('class');` and everything works except for when I try to get the defined stream's attribute name and type, I'm getting this error-> **trail.js:285 Uncaught TypeError: definedStreamMap.slice is not a function** ---> *My original problem* But thanks a lot for cleaning up this code: much easier to work with. Would appreciate your input in getting this solve. Thanks –  Sep 06 '16 at 11:45
  • Can you post an example of `createdDefinedStreamArray`, so we can see where exactly those attributes are. – Shilly Sep 06 '16 at 12:01
  • I have added the `createdDefinedStreamArray` definition and populating method in the question itself. –  Sep 07 '16 at 03:26
  • A JSON representation of the first row of the array would've sufficed. :) But anyway, you have an issue with the two for loops. The inner loop from 0 to 1 isn't correct. When c = 0, you correctly set attrNm to cell[0] and it's value to cell[1], but when c becomes 1, you overwrite this and set attrNm to cell[1] and set attrTp also to cell[1]. Remove the inner loop and just replace c with 0. If you still have issues after, check if those attrTp and AttrNm values are correctly coming out of the table with a simple console.log. – Shilly Sep 07 '16 at 10:22
  • The issue is not in the `createdDefinedStream` array since I'm able to retrieve the values stored here successfully in my other methods. The only problem is here. `var attrNum = createdDefinedStreamArray[count][4]; for(var f=0;f –  Sep 07 '16 at 11:01
  • Are `count` and `f` the correct values then? Since you use alot of `counter - 1` syntax. What's the value of createdDe‌​finedStreamArray[cou‌​nt][2] when the error pops up? Just put a breakpoint there and inspect the element in the debugger. – Shilly Sep 07 '16 at 11:54