0

I'm working on an application where data coming from the server (JSON) is partly displayed in a table. The user can select some rows, which are then added to another section with more detailed data.

Here is a sample of such JSON:

Sample JSON:

{
    "error": false,
    "pageIndex": "0",
    "resultset": [{
        "title": "Google",
        "CreationDate": "Mar 14, 2017 4:06:00 PM",
        "location": "USA",
        "path": "www.google.com",
        "image": "www.google.com/images/logo.jpg"
    }, {
        "title": "Global",
        "CreationDate": "Mar 14, 2017 4:06:00 PM",
        "location": "Global",
        "path": "www.abc.com",
        "image": "www.abc.com/images/logo.jpg"
    }, {
        "title": "Yahoo",
        "CreationDate": "Mar 14, 2017 4:06:00 PM",
        "location": "Europe",
        "path": "www.yahoo.com",
        "image": "www.yahoo.com/images/logo.jpg"
    }, {
        "title": "Amazon",
        "CreationDate": "Mar 14, 2017 4:06:00 PM",
        "location": "Europe",
        "path": "www.amazon.com",
        "image": "www.amazon.com/images/logo.jpg"
    }, {
        "title": "XYZ",
        "CreationDate": "Mar 14, 2017 4:06:00 PM",
        "location": "Europe",
        "path": "www.xyz.com",
        "image": "www.xyz.com/images/logo.jpg"
    }
    }],
    "totalMatches": 35
}

I populate the table from this, with some information displayed in the table columns, but also storing the whole record's data as JSON in the value attribute of each row's checkbox.

So, now I select a row using the checkbox from the table, and click on the 'Save' button which would then append the data to a static div with class="container".

However, if a particular div with the same weburl (as shown in the code) already exists inside the display div.container, it shouldn't add that a second time.

  1. Select A & D from the table shown in the screenshot and click on 'Save'.

  2. A & D get appended to div.container.

  3. Now, select A,D,G,J from the table.

Current situation: Nothing is added, and alert is shown as "Data already exists!"

Ideal behaviour: G & J should get appended to div.box and alert should be shown as "A already exists!".

I've tried to store all the urls from the div.parent in an array. And similarly, had stored the url of each JSON row selected from the table in a variable.

Next, I'm trying to compare if the tableURL (the URL of the selected row) exists in the DOM, then do not add it.

But, somehow it doesn't work! How do I achieve this?

Note: URL(weburl) is going to be unique here. Hence, taking that for comparison.

Here is the HTML with the table already populated (but not the value attributes of the input elements, which would have URL-encoded JSON):

<!doctype html>

    <html>
        <head>
            <style>
                table, th, td {
                    border: 1px solid #ddd;
                    border-collapse: collapse;
                    padding: 10px;
                }

                .parent {
                    height: 25%;
                    width: 90%;
                    padding: 1%;
                    margin-left: 1%;
                    margin-top: 1%;
                    border: 1px solid black;

                }

                .parent:nth-child(odd){
                    background: skyblue;
                }

                .parent:nth-child(even){
                    background: green;
                }

            </style>
        </head>
        <body>
            <table>
                <tr>
                    <th>Select</th>
                    <th>Name</th>
                    <th>Website</th>
                </tr>
                <tr>
                    <td><input type="checkbox" class="selectRow"></td>
                    <td class="name">A</td>
                    <td class="weburl"><a href="abc.com">ABC</a></td>
                </tr>
                <tr>
                    <td><input type="checkbox" class="selectRow"></td>
                    <td class="name">D</td>
                    <td class="weburl"><a href="def.com">DEF</a></td>
                </tr>
                <tr>
                    <td><input type="checkbox" class="selectRow"></td>
                    <td class="name">G</td>
                    <td class="weburl"><a href="ghi.com">GHI</a></td>
                </tr>
                <tr>
                    <td><input type="checkbox" class="selectRow"></td>
                    <td class="name">J</td>
                    <td class="weburl"><a href="jkl.com">JKL</a></td>
                </tr>
            </table>

            <button onclick="saveData()">Save</button>

            <br />

            <div class="container">

            </div>

            <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
            <script>


                var content = "";
                dispUrl = [];
                function saveData(){


                $('input[name="selectRow"]:checked').map(function(count) {
                    var myJSON =  JSON.parse(decodeURIComponent(this.value));
                    var tableDataUrl = myJSON.weburl;
                    content += '<div class="parent"><label class="dataLabel">Name:</label>'+myJSON.name+'<label class="dataLabel">Website:</label><a href="'+myJSON.weburl+'" class="myLink"></div>';

                    $('.parent .myLink').each(function() {
                       dispUrl.push($(this).attr('href'));
                     });

                    //console.log(linkArr);

                var isRendered = $.inArray(tableDataUrl, dispUrl);
                //alert(isRendered);

                  if(!isRendered) { 
                    $('.container').html(content);
                    resetEvents();
                  } else {
                    alert("Div already added to the result list!");
                  }  

             }

            }

            </script>
        </body>
    </html>

Edit:

Lets say in the table, I'd want the following:

  1. checkbox to select the particular row.
  2. title (lets say Google for e.g.) which is a hyperlink with href = path.
  3. creation date.

Now, in the content to be displayed(like we did earlier), after I select a row, lets say I want to display : title(with a hyperlink to path), location, image.

trincot
  • 317,000
  • 35
  • 244
  • 286
Sunny
  • 902
  • 3
  • 18
  • 41

2 Answers2

2

You could use this working snippet:

function createTable() {
    $.getJSON("https://api.randomuser.me/?results=25", function(data) {
        // First, clear the table
        $('#datatable tr:has(td)').remove();
        data.results.forEach(function (record) {
            var json = JSON.stringify(record);
            $('#datatable').append(
                $('<tr>').append(
                    $('<td>').append(
                        $('<input>').attr('type', 'checkbox')
                                    .addClass('selectRow')
                                    .val(json)
                    ),
                    $('<td>').append(
                        $('<a>').attr('href', record.picture.thumbnail)
                                .addClass('imgurl')
                                .attr('target', '_blank')
                                .text(record.name.first)
                    ),
                    $('<td>').append(record.dob)
                )
            );
        })
    }).fail(function(error) {
        console.log("**********AJAX ERROR: " + error);
    });            
}

function saveData(){
    // Scrape the URLs that were already collected into a Set:
    var used = new Set($('.myLink').map(function () {
        return $(this).attr('src');
    }).get());
    var errors = [];
    $('input.selectRow:checked').each(function(count) {
        // Get the JSON that is stored as value for the checkbox
        var obj = JSON.parse($(this).val());
        // See if this URL was already collected (that's easy with Set)
        if (used.has(obj.picture.thumbnail)) {
            errors.push(obj.name.first);
        } else {
            // Append it to the collection (use jQuery for appending)
            $('.container').append(
                $('<div>').addClass('parent').append(
                    $('<label>').addClass('dataLabel').text('Name: '),
                    obj.name.first + ' ' + obj.name.last,
                    $('<br>'), // line-break between name & pic
                    $('<img>').addClass('myLink').attr('src', obj.picture.thumbnail), $('<br>'),
                    $('<label>').addClass('dataLabel').text('Date of birth: '),
                    obj.dob, $('<br>'),
                    $('<label>').addClass('dataLabel').text('Address: '), $('<br>'),
                    obj.location.street, $('<br>'),
                    obj.location.city + ' ' + obj.location.postcode, $('<br>'),
                    obj.location.state, $('<br>')
                )
            );
        }
        // Clear checkbox:
        $(this).prop('checked', false)
    });
    if (errors.length) 
        alert('The following were already selected:\n' + errors.join('\n'))
}
table, th, td {
    border: 1px solid #ddd;
    border-collapse: collapse;
    padding: 10px;
}

.parent {
    height: 25%;
    width: 90%;
    padding: 1%;
    margin-left: 1%;
    margin-top: 1%;
    border: 1px solid black;
}

.parent:nth-child(odd){
    background: skyblue;
}

.parent:nth-child(even){
    background: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button onclick="createTable()">Load Table</button>
<table id="datatable">
    <tr><th>Select</th><th>Name</th><th>DOB</th></tr>
</table>
<button onclick="saveData()">Save</button>
<br />
<div class="container"></div>
trincot
  • 317,000
  • 35
  • 244
  • 286
  • Thank you so much for the help! Just one clarification, how do I get the values that are not displayed in the table, but are there in the JSON through which the table data is populated? For example, let's say in the 'obj' you've created, you're only receiving the values which are showing the table. But the JSON contains a lot of other properties which I'd want to display. In that case, how do I display those while appending to div.container ? – Sunny Apr 06 '17 at 08:02
  • I have updated my answer including some dummy data (which in your case would have been parsed from JSON which you received via Ajax, I assume). The parsed data then needs to be keyed by weburl for faster look-up, and finally the use of it becomes rather simple. See update which also displays a property that is not in the table, only in the data. NB: don't call variables `json` when they are not JSON strings, but JavaScript arrays/objects, which is *not* JSON any more. It is the text version of it that is called JSON, before being parsed. – trincot Apr 06 '17 at 09:42
  • OK, but the principle is the same. Do you have any issue in implementing it still? – trincot Apr 06 '17 at 10:00
  • How could I use - "var keyedData= JSON.parse(decodeURIComponent(this.value)); " here? Since, I'm getting the JSON through a URL. I believe this method is causing a problem! – Sunny Apr 06 '17 at 10:07
  • Just do it like you did before, but don't assign to *keyedData*, which is something additional I provided. Assign it to *dataFromJSON*, and then continue with the code I provided which assigns to *keyedData*. I updated the fiddle to use your JSON as a literal, but that first assignment needs to be replaced by the `JSON.parse(...)` assignment. – trincot Apr 06 '17 at 10:12
  • Sorry, but I'm a little confused now.Please check the fiddle here and tell me if this is correct. Thank you so much for all the help! https://jsfiddle.net/Sunny1719/Lvztu6x3/ – Sunny Apr 06 '17 at 10:28
  • What do you expect `this.value` to be in `decodeURIComponent(this.value)`? Didn't you already have the JSON to build the table? Anyway, `this` in a jQuery click handler refers to the clicked element, so you cannot expect `this.value` to be anything related to your JSON. – trincot Apr 06 '17 at 11:03
  • So, in that case, should I get the JSON outside the function and then use it? Can't I use the existing value of each of the checkbox in the table because that's already assigned to the respective JSON object? – Sunny Apr 06 '17 at 11:42
  • Just get the JSON like you already had it working (or didn't you?), and make sure that the variable `dataFromJSON` gets the JavaScript array that is the parsed JSON. I don't know what you mean with *"assigned to the respective JSON"*... you only have one JSON, which you parse upon receipt, and use to populate your table (that is what I understood). – trincot Apr 06 '17 at 11:49
  • ok, I'd updated the fiddle now. NOw, you can see, I've written a function called createTable() which creates a table on clicking the 'Create Table' button. Also, if you inspect the checkbox there you could find that it has value field which has the entire object associated to it. Here's the updated fiddle.. https://jsfiddle.net/Sunny1719/Lvztu6x3/1/ – Sunny Apr 06 '17 at 12:25
  • I'd also created a new fiddle. https://jsfiddle.net/Sunny1719/55Lb84m2/ – Sunny Apr 06 '17 at 12:52
  • I updated the snippet in my answer. Please realise that you never explained that you stored JSON in the value attribute of the checkboxes. Next time you really should give all the pieces of the information that are necessary to understand the question, **in** your question. – trincot Apr 06 '17 at 13:19
  • I'm sorry about not being descriptive and clear enough in the question. It works perfectly as expected! I don't know how to thank you for all the help! Yet, thanks a ton for all the help! I guess I could only thank you enough by helping someone in need! – Sunny Apr 07 '17 at 03:58
  • Ok, there's a minor issue in the table. I'm using it in a pop-up. Hence, once I close the pop-up and re-open it, the table data seem to appear twice! How could I avoid that? I'd asked a similar question earlier here and used html instead of append. But how do I use it here becaue we've multiple append -> http://stackoverflow.com/questions/43052440/data-being-added-twice-on-selecting-from-table-using-checkbox – Sunny Apr 07 '17 at 05:51
  • You can clear the rows (except the header row) with this: `$('#datatable tr:has(td)').remove();`. I added it to my answer. Pressing the "Create table" a second time will no longer double the number of rows. – trincot Apr 07 '17 at 06:10
  • 1
    Perfect! Thank you, take a bow Sir! – Sunny Apr 07 '17 at 06:33
  • I'd added another question in succession to this one. Do you mind taking a look into that? http://stackoverflow.com/questions/43275596/save-the-dynamically-created-dom-and-create-a-json – Sunny Apr 07 '17 at 10:28
1

i made some changes to your code. kindly go through comments and ask me if you need help with it. i dont know what u actually wanted to do, but i have created conditions which check whether the link is already added or not, and you cant place the respective code within those conditions:

var addedUrls;
function saveData() {
    addedUrls = [];

    var addedElements  = $(".myLink");
    for(var i = 0;i<addedElements.length;i++){
        //adds links present in .container class to addedUrls array
        addedUrls.push($(addedElements[i]).attr("href"));
    }

    var selectedElements = $(".selectRow:checked");
    for(var i = 0;i<selectedElements.length;i++){
        var selectedLink = $(selectedElements[i]).parent().next().next().text();
        if($.inArray( selectedLink, addedUrls ) == -1){
            //if the selected link is not present .container
        }
        else{
            //if the selected link is alread present in .container
        }
    }

}
Sahal Tariq
  • 198
  • 1
  • 9