0

I've a table which gets updated based on JSON data. Each row in the table has a checkbox which holds the value of the corresponding JSON object, which is basically the information about any of the users. On selecting any of the rows, and saving to display the selected user profile in 'div.parent' which gets appended to 'div.container', I'm also storing the selected JSON object in an array 'savedData'.

Now, I've some swap buttons using which I can swap each of the 'div.parent' with the next or previous 'div.parent'. So, on swapping the, the DOM structure changes accordingly. But, how do I sort 'savedData' array, in order to match the swapping order? For e.g., for the first 'div.parent' in the DOM, the corresponding object should be at 'savedData[0]'. Likewise, for the 2nd 'div.parent' in the DOM, the corresponding object should be at 'savedData[1]'.

How do I fix this?

function createTable() {
   $.getJSON("https://api.randomuser.me/?results=5", function(data) {
    $('#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);
   });            
  }

  var savedData = new Map; // Keyed by image URL. Start with nothing.

  function saveData(){
   var errors = [];
   // Add selected to map
   $('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 (savedData.get(obj.picture.thumbnail)) {
     errors.push(obj.name.first);
    } else {
     // Append it to the Map:
     savedData.set(obj.picture.thumbnail, obj);
    }
   });
   refreshDisplay();
   if (errors.length) {
    alert('The following were already selected:\n' + errors.join('\n'));
   }
  }

  function refreshDisplay() {
   $('.container').html('');
   savedData.forEach(function (obj) {
    // Reset container, and append collected data (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>'),
      $('<button>').addClass('removeMe').text('Delete'),
      $('<button>').addClass('top-btn').text('Swap with top'),
      $('<button>').addClass('down-btn').text('Swap with down')
     ) 
    );
    resetEvents();
   })
   // Clear checkboxes:
   $('.selectRow').prop('checked', false);
  }

  function logSavedData(){
   // Translate Map to array of values:
   var data = Array.from(savedData, function (pair) {
    return pair[1];
   });
   // Convert to JSON and log to console. You would instead post it
   // to some URL, or save it to localStorage.
   console.log(JSON.stringify(data, null, 2));
  }

  $(document).on('click', '.removeMe', function() {
   var key = $('.myLink', $(this).parent()).attr('src');
   // Delete this from the saved Data
   savedData.delete(key);
   // And redisplay
   refreshDisplay();
  });
  
   /* Swapping the displayed articles in the result list */
   function resetEvents() {

    $(".top-btn, .down-btn").unbind('click');

    handleEvents();
    
    $('.down-btn').click(function() {
     var toMove1 = $(this).parents('.parent');

     $(toMove1).insertAfter($(toMove1).next());

     handleEvents();
    });

    $('.top-btn').click(function() {
     var toMove1 = $(this).parents('.parent');
     
     $(toMove1).insertBefore($(toMove1).prev());
     handleEvents();
    });

   }
    
   /* Disable top & down buttons for the first and the last article respectively in the result list */
   function handleEvents() {
    $(".top-btn, .down-btn").prop("disabled", false).show();

    $(".parent:first").find(".top-btn").prop("disabled", true).hide();

    $(".parent:last").find(".down-btn").prop("disabled", true).hide();
   }
   
   $(document).ready(function(){
    $('#showExtForm-btn').click(function(){
     $('#extUser').toggle();
    });
    $("#extArticleForm").submit(function(){

                    addExtUser();
                    return false;
               });
   });
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;
  }
  
  label {
   float: left;
   width: 80px;
  }
  input {
   width: 130px;
  }
<button onclick="createTable()">Create Table</button>
  <table id="datatable">
   <tr><th>Select</th><th>Name</th><th>DOB</th></tr>
  </table>
  <button onclick="saveData()">Save Selected</button>
  <br />
  <div class="container"></div>
  <button onclick="logSavedData()">Get Saved Data</button>
Sunny
  • 902
  • 3
  • 18
  • 41
  • these question are about basic json manipulation – madalinivascu Apr 11 '17 at 06:33
  • This question is too broad. Please ask one question at a time, and provide the code you have tried with (in this case: for achieving point 6), specifying the specific issue you bumped into. For point 8 you should ask a separate question, and give much more information and code of how you intend to ask users for data, again providing the code you have tried to implement that, and the *specific* problem you bumped into. – trincot Apr 11 '17 at 07:03
  • Sorry about the confusion! I'd updated my code and description now. Also, had seperated the questions. http://stackoverflow.com/questions/43343612/add-external-object-to-an-existing-array – Sunny Apr 11 '17 at 11:08

1 Answers1

1

In the case you want to keep specific order a Map is less suitable. In that case use a standard array. The advantage is then also that this array is exactly what you want to export as JSON. The downside is that you need to iterate over that array to see whether an element is already included (with find for instance).

The event handler reattachment you do can be simply avoided by using event delegation, just like you already had it for the delete action (with $(document).on syntax.

I would suggest to not perform the swap on the parent divs directly, but to apply them to the savedData array, and then use the refreshDisplay function to display the result from that array.

See the snippet below:

function createTable() {
    $.getJSON("https://api.randomuser.me/?results=5", function(data) {
        $('#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);
    });            
}

var savedData = []; // The objects as array, so to have an order.

function saveData(){
    var errors = [];
    // Add selected to array
    $('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 (savedData.find(record => record.picture.thumbnail === obj.picture.thumbnail)) {
            errors.push(obj.name.first);
        } else {
            // Append it
            savedData.push(obj);
        }
    });
    refreshDisplay();
    if (errors.length) {
        alert('The following were already selected:\n' + errors.join('\n'));
    }
}

function refreshDisplay() {
    $('.container').html('');
    savedData.forEach(function (obj) {
        // Reset container, and append collected data (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>'),
                $('<button>').addClass('removeMe').text('Delete'),
                $('<button>').addClass('top-btn').text('Swap with top'),
                $('<button>').addClass('down-btn').text('Swap with down')
            ) 
        );
    })
    // Clear checkboxes:
    $('.selectRow').prop('checked', false);
    handleEvents();
}

function logSavedData(){
    // Convert to JSON and log to console. You would instead post it
    // to some URL, or save it to localStorage.
    console.log(JSON.stringify(savedData, null, 2));
}

function getIndex(elem) {
    return $(elem).parent('.parent').index();
}

$(document).on('click', '.removeMe', function() {
    // Delete this from the saved Data
    savedData.splice(getIndex(this), 1);
    // And redisplay
    refreshDisplay();
});

/* Swapping the displayed articles in the result list */
$(document).on('click', ".down-btn", function() {
    var index = getIndex(this);
    // Swap in memory
    savedData.splice(index, 2, savedData[index+1], savedData[index]);
    // And redisplay
    refreshDisplay();
});

$(document).on('click', ".top-btn", function() {
    var index = getIndex(this);
    // Swap in memory
    savedData.splice(index-1, 2, savedData[index], savedData[index-1]);
    // And redisplay
    refreshDisplay();
});
    
/* Disable top & down buttons for the first and the last article respectively in the result list */
function handleEvents() {
    $(".top-btn, .down-btn").prop("disabled", false).show();
    $(".parent:first").find(".top-btn").prop("disabled", true).hide();
    $(".parent:last").find(".down-btn").prop("disabled", true).hide();
}

$(document).ready(function(){
    $('#showExtForm-btn').click(function(){
        $('#extUser').toggle();
    });
    $("#extArticleForm").submit(function(){
        addExtUser();
        return false;
   });
});
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;
}

label {
    float: left;
    width: 80px;
}
input {
    width: 130px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button onclick="createTable()">Create Table</button>
<table id="datatable">
    <tr><th>Select</th><th>Name</th><th>DOB</th></tr>
</table>
<button onclick="saveData()">Save Selected</button>
<br />
<div class="container"></div>
<button onclick="logSavedData()">Get Saved Data</button>
trincot
  • 317,000
  • 35
  • 244
  • 286