0

I would like to know how to add input to each field in a table once I press edit using jquery. So basically I have 7 columns with 7 headings in the table for html and I want to be able to edit each field after pressing edit button which will be at the right side of the table for each row. After I add the input field in each column for that specific row and once the input is in, I want to call my update api using ajax. This is my html code.

<div id="table-wrapper"> 
    <div id="table-scroll">
    <table id="results" class="hidden" cellspacing=10px>
        <thead>
            <tr class = "spacing">
                <th>SAM ID</th>
                <th>Item Description</th>
                <th>Issued QTY</th>
                <th>Opening QTY</th>
                <th>Closing QTY</th>
                <th>Corrupted QTY</th>
                <th>Remarks</th>
            </tr>
        </thead>
        <tbody id="bResults">
        </tbody>
    </table>
    </div>
    </div>

This is my js code connected to the html.

function search(){

var samId = $('#samId').val();
var postData = { "samId": samId };
var postJSON = JSON.stringify(postData);
$.ajax({
    url: "http://localhost:3000/api/queryRecord", // server url
    type: "POST", //POST or GET
    contentType: "application/json",
    data: postJSON, // data to send in ajax format or querystring format
    dataType : "JSON", //dataType is you telling jQuery what kind of 
    response to expect
    success: function(response) {
        alert('success');
         if(response){
            var len = response.length;
            var txt = "";
            if(len > 0){
                for(var i=0;i<len;i++){
                    if(response[i].samID && response[i].itemDescription){
                        txt += "<tr class='rowdata'><td>"+response[i].samID 
                        +"</td><td>"+response[i].itemDescription+"</td><td>"
                        +response[i].issuedQTY + "</td>
                        <td>"+response[i].openingQTY + "</td>
                        <td>"+response[i].closingQTY
                        +"</td><td>"+response[i].corruptedQTY+"</td>
                        <td>"+response[i].Remarks+"</td><td>" 
                        + "<input class='button-edit' type='submit' 
                        value='Edit' onclick = 'edit()' />" 
                        +"</td></tr>";
                    }
                }

                $("#bResults").empty();
                if(txt != ""){
                    $("#results").removeClass("hidden");
                    $("#bResults").append(txt);
                }
            }
        }
    },
    error: function(response) {
        alert('error');
    }
});
event.preventDefault();
}

 function edit(){
 var currentTD = $(this).parents('tr').find('td');
      if ($(this).html() == 'Edit') {                  
          $.each(currentTD, function () {
              $(this).prop('contenteditable', true)
          });
      } else {
         $.each(currentTD, function () {
              $(this).prop('contenteditable', false)
          });
      }

      $(this).html($(this).html() == 'Edit' ? 'Save' : 'Edit')
}

My search() works fine but just wanted to show how my response is being coded. This edit() is what I have basically but I don't really know how to use as the code is from another question Making row editable when hit row edit button due to not having any clue about the way to do this edit and adding a input field for people to edit in that particular row. I am using mongodb as the database as well. Do explain it in a simpler way for me to understand better. Thanks!

UPDATE Following according to Mohamed-Yousef

function search(){

var samId = $('#samId').val();
var postData = { "samId": samId };
var postJSON = JSON.stringify(postData);
$.ajax({
    url: "http://localhost:3000/api/queryRecord", // server url
    type: "POST", //POST or GET
    contentType: "application/json",
    data: postJSON, // data to send in ajax format or querystring format
    dataType : "JSON", //dataType is you telling jQuery what kind of 
    response to expect
    success: function(response) {
        alert('success');
         if(response){
            var len = response.length;
            var txt = "";
            if(len > 0){
                for(var i=0;i<len;i++){
                    if(response[i].samID && response[i].itemDescription){
                        txt +="<tr class='rowdata'><td>"+response[i].samID+ 
                              "</td>"+<td>"+response[i].itemDescription+
                               "</td>"+"<td>"+response[i].issuedQTY + 
                               "</td>"+"<td>"+response[i].openingQTY + 
                               "</td>"+"<td>"+response[i].closingQTY+
                               "</td>"+"<td>"+response[i].corruptedQTY+
                               "</td>"+"<td>"+response[i].Remarks+"</td>"
                               +"<td><input class='button-edit' 
                               type='submit' value='Edit' onclick = 'edit()' 
                               /></td>"+"</tr>";
                    }
                }

                $("#bResults").empty();
                if(txt !== ""){
                    $("#results").removeClass("hidden");
                    $("#bResults").append(txt);
                }
            }
        }
    },
    error: function(response) {
        alert('error');
    }
});
event.preventDefault();
}
 function edit(el){
 var currentTD = $(el).closest('tr').find('td').not($(el).closest('td'));
      if ($(this).html() == 'Edit') {                  
          $.each(currentTD, function () {
              $(this).prop('contenteditable', true)
          });
      } else {
         $.each(currentTD, function () {
              $(this).prop('contenteditable', false)
          });
      }

      $(el).val($(el).val() == 'Edit' ? 'Save' : 'Edit')
}

Does not seem to work and still gives the error Uncaught TypeError: Cannot read property 'createDocumentFragment' of undefined

Another answer I did according to Bryan Dellinger was using knockout.js

<table id="results" class="hidden" cellspacing=10px>
        <thead>
            <tr class = "spacing">
                <th>SAM ID</th>
                <th>Item Description</th>
                <th>Issued QTY</th>
                <th>Opening QTY</th>
                <th>Closing QTY</th>
                <th>Corrupted QTY</th>
                <th>Remarks</th>
            </tr>
        </thead>

             <tbody id="bResults" data-bind="foreach: txt">
        <tr>
            <td>
   <!-- ko if: buttonText() === 'Save' -->
            <input data-bind="textInput: samID">
   <!-- /ko -->
       <!-- ko if: buttonText() === 'Edit' -->
            <span data-bind="text: samID"></span>
   <!-- /ko -->
            </td>
        <td>
   <!-- ko if: buttonText() === 'Save' -->
            <input data-bind="textInput: itemDescription">
   <!-- /ko -->
       <!-- ko if: buttonText() === 'Edit' -->
            <span data-bind="text: itemDescription"></span>
   <!-- /ko -->
        </td>
        <td>
    <!-- ko if: buttonText() === 'Save' -->
            <input data-bind="textInput: issuedQTY">
   <!-- /ko -->
       <!-- ko if: buttonText() === 'Edit' -->
            <span data-bind="text: issuedQTY"></span>
   <!-- /ko -->
        </td>
        <td>
    <!-- ko if: buttonText() === 'Save' -->
            <input data-bind="textInput: openingQTY">
   <!-- /ko -->
       <!-- ko if: buttonText() === 'Edit' -->
            <span data-bind="text: openingQTY"></span>
   <!-- /ko -->
        </td>
        <td>
    <!-- ko if: buttonText() === 'Save' -->
            <input data-bind="textInput: closingQTY">
   <!-- /ko -->
       <!-- ko if: buttonText() === 'Edit' -->
            <span data-bind="text: closingQTY"></span>
   <!-- /ko -->
        </td>
        <td>
    <!-- ko if: buttonText() === 'Save' -->
            <input data-bind="textInput: corruptedQTY">
   <!-- /ko -->
       <!-- ko if: buttonText() === 'Edit' -->
            <span data-bind="text: corruptedQTY"></span>
   <!-- /ko -->
        </td>
        <td>
    <!-- ko if: buttonText() === 'Save' -->
            <input data-bind="textInput: corruptedQTY">
   <!-- /ko -->
       <!-- ko if: buttonText() === 'Edit' -->
            <span data-bind="text: corruptedQTY"></span>
   <!-- /ko -->
        </td>
                    <td>
    <!-- ko if: buttonText() === 'Save' -->
            <input data-bind="textInput: Remarks">
   <!-- /ko -->
       <!-- ko if: buttonText() === 'Edit' -->
            <span data-bind="text: Remarks"></span>
   <!-- /ko -->
        </td>
        <td><button data-bind="text: buttonText, click: $parent.click">
        </button></td>
        </tr>
        </tbody>
    </table>
  <script src="js/jquery-3.2.1.min.js"></script>
  <script src="js/mainpage.js"></script>
  <script 
  src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-
   min.js"></script> 
  <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1
  /knockout.mapping.min.js"></script>  

This is the js

function search(){

var samId = $('#samId').val();
var postData = { "samId": samId };
var postJSON = JSON.stringify(postData);
$.ajax({
    url: "http://localhost:3000/api/queryRecord", // server url
    type: "POST", //POST or GET
    contentType: "application/json",
    data: postJSON, // data to send in ajax format or querystring format
    dataType : "JSON", //dataType is you telling jQuery what kind of response to expect
    success: function(response) {
        alert('success');
         if(response){
            var len = response.length;
            var txt = "";
            if(len > 0){
                for(var i=0;i<len;i++){
                    if(response[i].samID && response[i].itemDescription){
                        txt = [{
                                "samID": response[i].samID,
                              "itemDescription":response[i].itemDescription,
                               "issuedQTY": response[i].issuedQTY,
                                "openingQTY": response[i].openingQTY,
                                "closingQTY": response[i].closingQTY,
                                "corruptedQTY": response[i].corruptedQTY,
                                "editMode" : false,
                                "Remarks": response[i].Remarks,
                                "buttonText": "Edit"
                        }]
                    }
                }

                $("#bResults").empty();
                if(txt != ""){
                    $("#results").removeClass("hidden");
                    $("#bResults").append(txt);
                }
            }
        }
    },
    error: function(response) {
        alert('error');
    }
});
event.preventDefault();
}
Ong Kong Tat
  • 1,172
  • 2
  • 9
  • 22
  • I'll just put this as a comment as you are requesting just a jquery solution. but jquery with knockoutjs makes this kind of thing very easy. I created a fiddle where you can click edit and update the fields. https://jsfiddle.net/0o89pmju/2/ – Bryan Dellinger Jun 23 '17 at 02:03
  • @BryanDellinger Hi I don't really understand your `viewModel()` function on how it gets triggered in this code. Does the name matter or can I change it to another name and do I have to bind to a click? Don't mind but could you explain it to me? – Ong Kong Tat Jun 23 '17 at 11:40
  • sure knockoutjs is an MVVM framework. model view viewmodel. the viewmodel is the go between from the model (in this case the raw data for your table which I called items. and the view (the html). the viewmodel allows two way bindings which makes for dynamic actions. there is a great and kind of fun interactive tutorial here. http://learn.knockoutjs.com/ – Bryan Dellinger Jun 23 '17 at 11:52
  • @BryanDellinger is there a need to download any additional things because it is giving me `undefined ko` ? – Ong Kong Tat Jun 23 '17 at 13:52
  • you will need the knockoutjs library and possibly the knockout mapping library. (If you go to my fiddle in the external resources you can see the CDN for them there) https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js and https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js – Bryan Dellinger Jun 23 '17 at 14:39
  • @BryanDellinger I updated my question using knockout.js but I still get `ko is not defined` – Ong Kong Tat Jun 24 '17 at 02:15

1 Answers1

1

I think The problem is : by using $(this) inside your edit() function its refer to object I don't know for window or something but its not for an edit button .. so you can pass edit(element) as an argument and on html use onclick="edit(this)"

And while you use input .. use .val() instead of .html()

And to avoid the td which has your edit input you can use .not()

so your code should looks like

function edit(el){
 var currentTD = $(el).closest('tr').find('td').not($(el).closest('td')); // tds except the td which closest to the edit button
 if ($(el).val() == 'Edit') {                  
     $.each(currentTD, function () {
       $(this).prop('contenteditable', true)
     });
  } else {
     $.each(currentTD, function () {
       $(this).prop('contenteditable', false)
     });
  }

  $(el).val($(el).val() == 'Edit' ? 'Save' : 'Edit')
}

And on html use type="button" no need to use submit

<input class='button-edit' type='button'  value='Edit' onclick = 'edit(this)' /> 
//--------------------------------^-------------------------------------^--------

And the row HTML structure should be like

txt += "<tr class='rowdata'><td>"+response[i].samID+"</td>"
  +"<td>"+response[i].itemDescription+"</td>"
  +"<td>"+response[i].issuedQTY + "</td>"
  +"<td>"+response[i].openingQTY + "</td>"
  +"<td>"+response[i].closingQTY+"</td>"
  +"<td>"+response[i].corruptedQTY+"</td>"
  +"<td>"+response[i].Remarks+"</td>"
  +"<td><input class='button-edit' type='submit' value='Edit' onclick = 'edit()' /></td>" 
  +"</tr>";

And use !== instead of != in if(txt != ""){

Mohamed-Yousef
  • 23,946
  • 3
  • 19
  • 28
  • It gave the same error as before `Uncaught TypeError: Cannot read property 'createDocumentFragment' of undefined` so I am guessing it has to do with how my `td` is structured. Forgot to state the error in my question sorry about that. – Ong Kong Tat Jun 23 '17 at 11:41
  • @OngKongTat answer updated .. when `.append()` or `.html()` be sure each line of code start/end with `"` or `'` and with a new line put `+` before first `"` .. So when trying to do the same thing again .. make the html first then add the concatenate variables to it – Mohamed-Yousef Jun 23 '17 at 17:53
  • It still gives the error. I updated my question according to your answer – Ong Kong Tat Jun 24 '17 at 01:59
  • So it turns out I had another function which had a response which was not the same as the one that I had in my `search()` which caused that error. Now I managed to figure it out by editing the code to correct response and thus it all worked out. Sorry for my mistake and thanks for your answer! – Ong Kong Tat Jun 26 '17 at 05:31