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, I'm also storing the selected JSON object in an array 'savedData'.

I also have an option of adding the user externally through a form which pops up on clicking 'Open External form' button. Now, I'm trying to create an object and store it in the same 'savedData' array on submitting that form. At the same time, the 'div.parent' should get generated & get appended to 'div.container' in the same format as it is for the the other users selected from the table.

Unfortunately, the 'div.parent' is not getting created, and the external object is not getting added.

Could you please help me 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;
               });
   });
   
   function addExtUser() {
    var name= $("#name").val();
    var imgsrc = $("#myImg").val();
    var dob = $("#dob").val();
    
    var errors = [];
                extObj = {};
    extObj = {};
    extObj["name"]["title"] = "mr";
    extObj["name"]["first"] = name;
    extObj["dob"] = dob;
    extObj["picture"]["thumbnail"] = imgsrc;
    savedData.push(extObj);
    if (savedData.get(imgsrc)) {
      errors.push(title);
     } else {
    $('.container').append(
     $('<div>').addClass('parent').append(
      $('<label>').addClass('dataLabel').text('Name: '),
      +name+
      $('<br>'), // line-break between name & pic
      $('<img>').addClass('myLink').attr('src', imgsrc), $('<br>'),
      $('<label>').addClass('dataLabel').text('Date of birth: '),
      +dob+ $('<br>'),
      $('<label>').addClass('dataLabel').text('Address: '), $('<br>'),
      +address+ $('<br>'),
      $('<button>').addClass('removeMe').text('Delete'),
      $('<button>').addClass('top-btn').text('Swap with top'),
      $('<button>').addClass('down-btn').text('Swap with down')
     ) 
    );
    resetEvents();
    
   }
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, textarea {
   width: 130px;
  }
  
  #extUser {
   border: 1px solid lightgrey;
   border-radius: 5px;
   display: none;
   padding: 10px;
   background-color: skyblue;
  }
  
  #extUserForm {
   margin: 3px;
   padding: 5px;
  }
<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>
  <button id="showExtForm-btn">Open External Form</button>
  
  <div id="extUser">
   <form id="extUserForm">
    <p>
     <label for="name">Name:</label>
     <input type="text" id="name" required>
    </p>
    <br />
    <p>
     <label for="myImg">Image:</label>
     <input type="url" id="myImg" required>
    </p>
    <br />
    <p>
     <label for="dob">DOB:</label>
     <input type="date" id="dob" required>
    </p>
    <br />
    <button onclick="addExtUser()">Submit</button>
   </form>
  </div>
Sunny
  • 902
  • 3
  • 18
  • 41

1 Answers1

1

There is an issue with the form submission:

  • you have onclick="addExtUser()" on the submit button, but although you return false in that function, this return value is ignored. It should have been onclick="return addExtUser()".

  • There is a listener to the form's submit event that also calls addExtUser. However, the id of the form is misspelled: it should be $("#extUserForm").submit instead of $("#extArticleForm").submit.

  • But you need only one way of calling addExtUser, so remove one of the above. I would suggest the second way (with the correction of the spelling).

You probably want the form to be hidden at first, so add style="display:none" to the HTML.

There is some duplication of code, as addExtUser has a lot of code in common with refreshDisplay: you should call refreshDisplay after having added the data to savedData.

Note that savedData.push is not a valid method on a Map, but I would suggest to use a plain array (see your other question on swapping records).

The way to define your object is quite similar to JSON syntax. This will not work:

extObj = {};
extObj["name"]["title"] = "mr";

But this will:

var extObj = {
    name: {
        title: "mr", // No ladies? :-)
        first: $("#name").val(),
        // Last name ?
    },
    dob: $("#dob").val(),
    picture: {
        thumbnail: $("#myImg").val()
    },
    location: { // maybe also ask for this info?
    }
};

Here is a snippet that implements all 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 = []; // The objects as array, so to have an order.

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.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();
    });
    $("#extUserForm").submit(function(e){
        addExtUser();
        return false;
   });
});

function addExtUser() {
    var extObj = {
        name: {
            title: "mr", // No ladies? :-)
            first: $("#name").val(),
            // Last name ?
        },
        dob: $("#dob").val(),
        picture: {
            thumbnail: $("#myImg").val()
        },
        location: { // maybe also ask for this info?
        }
    };
    savedData.push(extObj);
    refreshDisplay(); // Will show some undefined stuff (location...)
}
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>
<button id="showExtForm-btn">Open External Form</button>

<div id="extUser" style="display:none">
    <form id="extUserForm">
        <p>
            <label for="name">Name:</label>
            <input type="text" id="name" required>
        </p>
        <br />
        <p>
            <label for="myImg">Image:</label>
            <input type="url" id="myImg" required>
        </p>
        <br />
        <p>
            <label for="dob">DOB:</label>
            <input type="date" id="dob" required>
        </p>
        <br />
        <button>Submit</button>
    </form>
</div>
trincot
  • 317,000
  • 35
  • 244
  • 286
  • I'd added a pop-up which has previous next buttons. I've couple of issues with that which I'm not able to fix. Hope this is my last question on this topic though! - http://stackoverflow.com/questions/43361662/disable-the-first-previous-button-on-dynamic-page-numbers – Sunny Apr 12 '17 at 07:54
  • I'll have a look – trincot Apr 12 '17 at 07:55
  • I am able to add the same user twice. Do I need to validate it the same way like I did it earlier - if (savedData.get(obj.picture.thumbnail)) { errors.push(obj.name.first);} else { // Append it to the Map: savedData.set(obj.picture.thumbnail, obj);} – Sunny Apr 12 '17 at 12:31
  • No, I suggested to abandon the Map in the previous Q&A. It is not in the solution that I provided here. The snippet here refuses duplicates with a call to `find`, and new entries are added with `push`. – trincot Apr 12 '17 at 13:23
  • I've a small problem with the content disappearing when I add an external user. I've made some changes based on my requirement. Could you please help me Sir? http://stackoverflow.com/questions/43525692/dynamic-data-disappearing-on-adding – Sunny Apr 20 '17 at 17:03