I have a table that is created using javascript based on what is put in a list. This works fine in Jquery 3.4, but when I upgrade to 3.5 I am seeing this break.
HTML
<h5>Questions</h5>
<table id="questionTable" class="table q">
<thead>
</thead>
<tbody id="qTable"></tbody>
</table>
<div id="questionDiv">
<input type="button" value="Add Question" onclick="AddNewQuestion()" class="btn btn-primary"/>
</div>
<hr />
<div id="questionDiv">
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
Javascript
<script type="text/javascript">
$(document).ready(function () {
$(function () {
AddCurrentQuestions();
});
});
var table = document.getElementById("qTable");
var rowCount = table.rows.length;
var counter = rowCount.length;
function AddCurrentQuestions() {
var status = #Html.Raw(Json.Encode(Model.isNull));
if (status == false) {
#{ Model.QuestionList.Add(new Performance_Planning.ViewModel.QuestionViewModel.Questions());}
var questionItems = JSON.parse('#Html.Raw(Json.Encode(#Model.QuestionList))');
for (var i = 0; i < questionItems.length - 1; i++) {
var qItem = questionItems[i];
var questionDetail = qItem.Question;
//Create fields
var qTextCell = "<td><textarea id='QuestionList_" + i + "_Question' name='QuestionList[" + i + "].Question' class='Questions' /></td>";
var indexCell = "<td style='display:none'> <input name='QuestionList.Index' type='hidden' value='" + i + "' /></td>";
var removeCell = "<td align='center'><input id='btnDelLine'" + i + "type='button' value='Remove' onclick=\"removeRow('" + i + "')\" class='btn btn-primary' /></td>";
var newRow = "<tr id='qLineItem" + i + "'>" + indexCell + qTextCell + removeCell + "</tr>";
//Add row to table
$('#qTable').append(newRow);
//Add Values
$('#QuestionList_' + i + "_Question").val(questionDetail)
counter = i;
};
} else {
counter = 0;
AddNewQuestion();
}
};
function AddNewQuestion() {
#{ Model.QuestionList.Add(new Performance_Planning.ViewModel.QuestionViewModel.Questions());}
counter++;
//Create field
var indexCell = "<td style='display:none'> <input name='QuestionList.Index' type='hidden' value='" + counter + "' /></td>";
var qTextCell = "<td><textarea id='QuestionList_" + counter + "_Question' name='QuestionList[" + counter + "].Question' class='Questions' /></td>";
var removeCell = "<td align='center'><input id='btnDelLine'" + counter + "type='button' value='Remove' onclick=\"removeRow('" + counter + "')\" class='btn btn-primary' /></td>";
var newRow = "<tr id='qLineItem" + counter + "'>" + indexCell + qTextCell + removeCell + "</tr>";
$('#qTable').append(newRow);
};
function removeRow(id) {
var rowId = "qLineItem" + id;
var row = document.getElementById(rowId);
row.parentNode.removeChild(row);
};
</script>
}
What I end up seeing is that the remove button is treated as text in 3.5.1 but this doesn't occur with 3.4. I am unsure how to solve this issue or if I will need to figure out another way to write this page.
When I view the webpage and inspect the field I see it do the following:
<textarea id="QuestionList_0_Question" name="QuestionList[0].Question" class="Questions">
"</td><td align='center'><input id='btnDelLine'0type='button' value='Remove' onclick="removeRow('0')" class='btn btn-primary' /></td></tr></tbody></table>"
The textarea element should have a separate close tag. It is not allowed to self-close. So this is not valid HTML:
<textarea />
But this is:
<textarea></textarea>
Apparently, jQuery 3.5 is more strict in this. An inspection of the 3.5 changelog reveals that this is a consequence of the security fix they applied:
The main change in this release is a security fix, and it’s possible you will need to change your own code to adapt. Here’s why: jQuery used a regex in its jQuery.htmlPrefilter method to ensure that all closing tags were XHTML-compliant when passed to methods. For example, this prefilter ensured that a call like jQuery("<div class='hot' />") is actually converted to jQuery("<div class='hot'></div>"). Recently, an issue was reported that demonstrated the regex could introduce a cross-site scripting (XSS) vulnerability.
The HTML parser in jQuery <= 3.4.1 usually did the right thing, but there were edge cases where parsing would have unintended consequences. The jQuery team agreed it was necessary to fix this in a minor release, even though some code relies on the previous behavior and may break. The jQuery.htmlPrefilter function does not use a regex in 3.5.0 and passes the string through unchanged.
One can see how before 3.5, jQuery would actually change <textarea /> to <textarea></textarea> on the fly, thereby fixing the error you made. But now with version 3.5 jQuery no longer does that, and so your HTML remains invalid, leading to an unintended rendering where everything after <textarea /> ends up as content to that text area element.
Newb here...I have a table I created using the jQuery DataTables plugin. Everything is working as expected BUT I added a column that is an input. I'd like for users to be able to sort this column after putting in their values. It is a ranking system that is using quite a long list of items so they need to be able to sort after entering values so that they can keep track of what numbers they've used up to that point. I am setting my variable to be the input value on keyup but after I set the value, I can't sort the column by clicking on the header. It works for the other columns (from jQuery DataTable plugin). Also, if i hard code some text before if the td (before '+sortRank+') it also works as expected. Why is it not recognizing the values for sorting after I set them with jQuery? Thanks for you help!
$(document).ready(function() {
function GenerateTableFromJson(objArray,objArrayTwo,objArrayThree) {
var tableContent = '<table summary="GFSTechIntake" id="AllRequestsTable" style="width:100%"><thead><tr><th>Submit Priority</th><th>Your Prev Rank</th><th>Current Overall</th><th>Category</th>' + '<th>Status</th>' +' <th>Request Name</th>' + '<th>Problem Statement</th>' + '<th>Business Benefits</th><th>Dept(s)</th></tr></thead><tbody>';
var sortRank = "";
$('input.title').on('keyup',function(){
sortRank = $(this).val();
});
tableContent += '<tr class="allItemsTr">';
if(rank != ''){
tableContent += '<td class="allItemsPriority">'+sortRank+'<input class="title" placeholder=' + rank + ' value='+rank+'></td>';
} else {
tableContent += '<td class="allItemsPriority"><input class="title" placeholder=' + rank + '></td>';
}
tableContent += '<td class="prevRank">N/A</td>';
tableContent += '<td class="currentRank">N/A</td>';
}
return tableContent;
}
I have an $.ajax() request working properly, but i need to get 4 values(name, clientid, url, id) of < td >. $.val() doesn't work, because it only works on inputs.
I need to get the name, client Id , url and id from dynamically appended rows. I need those values so, when I click on the edit button of the selected row, it saves the changes I made.
How should I get the value? with $.html()? $.text()?
HTML
<div class="row">
<div class="col-md-12 overflow-table">
<table class="table" id="table">
<thead class="head-color thead-inverse">
<tr>
<th style="border-top-left-radius: 10px; border-left:1px solid transparent;">NAME</th>
<th>CLIENT-ID</th>
<th>URL</th>
<th style="border-top-right-radius: 10px; border-right:1px solid transparent;">ACTIONS</th>
</tr>
</thead>
<tbody id='table-redirect'>
<tr class='lightgrey'>
</tr>
<tr class='lightgrey'>
</tr>
<tr class='lightgrey'>
</tr>
<tr class='lightgrey'>
</tr>
</tbody>
</table>
</div>
</div>
JavaScript:
//change table content
$(document).on('click', '#editButton', function(e) {
var url = "http://mobisteinlp.com/redirect/redirect";
var name = $('#name1').val();
console.log(name);
var clientId = $('#client_id1').val();
console.log(clientId);
var redirectUrl = $('#url1').html();
console.log(redirectUrl);
var id = $('#hidden').val()
console.log(id);
var formData = new FormData();
formData.append('name1', name);
formData.append('client_id1', clientId);
formData.append('url1', redirectUrl);
formData.append('id', id);
console.log('test');
$.ajax({
url: url + "/editRedirect",
type: "POST",
dataType: "json",
data: formData,
contentType: false,
cache: false,
processData: false,
success: function(obj) {
var name, clientId, redirectUrl, id;
var rows = '';
$("tbody").empty('');
for (i = 0; i < obj.length; i++) {
rows += "<tr class='lightgrey'><th contenteditable='true'>" + obj[i].name + "</th><td>" + obj[i].client_id + "</td><td contenteditable='true' >" + obj[i].url + "</td><td><button type='button' id='editButton' class='btn btn-info'" + obj[i].client_id + "'><img class='col-md-2 edit nopad float-right' src='http://mobisteinlp.com/redirect/public/img/edit.svg'></button><a href='http://mobisteinlp.com/redirect/public/click.php/?id='" + obj[i].id + "'><img class='col-md-2 link nopad float-right' src='http://mobisteinlp.com/redirect/public/img/copy.svg'></a></td></td></tr>";
console.log('sucess!');
console.log(obj);
}
$("#table").append(rows);
},
error: function() {
console.log('error');
}
}); //END /editRedirect $.ajax()
}); //END $(document).on('click','#change',function(e)
The .text() method will return just the text within the element.
The .html() method will return the text, plus any HTML which might be contained within the element.
e.g. if your <td> looked like this for any reason:
<th class="clientID"><span>12345</span></th>
Then:
$(".clientID").text(); will return 12345
$(".clientID").html(); will return <span>12345</span>
So for your purposes you should use .text() to get just the actual text content to send to the server.
You can check all this in the jQuery documentation easily, as well, and by your own tests.
Now, to get a value within the specifically clicked row, you need to restrict by the row context in the markup. In the "click" event, this will be the button that was clicked, which is within the <tr>. The corresponding data is also within the <tr>.
So you can use the <tr> as the nearest element which encloses both the button and the data. Then if you give each <td> a class corresponding to what it represents (client ID, url, etc) as I've done above, you can do something like:
var tr = $(this).closest("tr"); //get the parent tr
var clientID = tr.find(".clientID").text(); //get the client ID text within the tr
var url = tr.find(".url").text(); //same for url, etc...
Lastly, your button clicks won't work properly because you're duplicating IDs. It will only ever work for the first button.
Change <button type='button' id='editButton' class='btn btn-info' to <button type='button' class='btn btn-info editButton' (use a class instead of an id)
and change $(document).on('click', '#editButton', function(e) { to $(document).on('click', '.editButton', function(e) { (simply, # is changed to .)
1) you appending multiple row with duplicate id . id should be unique for each element . just use class name instead of id .
2) appending one th and extra td
<th contenteditable='true'>" + obj[i].name + "</th>
Updated code with class name
` <tr class='lightgrey'>
<td contenteditable='true' class="name">" + obj[i].name + "</td>
<td class="client_id">" + obj[i].client_id + "</td>
<td contenteditable='true' class="url" >" + obj[i].url + "</td>
<td>
<button type='button' class='btn btn-info editButton'" + obj[i].client_id + "'>
<img class='col-md-2 edit nopad float-right' src='http://mobisteinlp.com/redirect/public/img/edit.svg'>
</button><a href='http://mobisteinlp.com/redirect/public/click.php/?id='" + obj[i].id + "'>
<img class='col-md-2 link nopad float-right' src='http://mobisteinlp.com/redirect/public/img/copy.svg'></a>
</td>
</tr>`
Jquery :
Setup class name for each td and traverse and access it easily like this
`$(document).on('click', '.editButton', function(e) {
var tr = $(this).closest("tr");
var client_id = tr.find(".client_id").text();
var url = tr.find(".url").text();
var name = tr.find(".name").text();
});`
Get the different between these commands, then you can fix your by yourself
The following used to retreive data from a value attribute(normally input tags).
//Here id is id name of your element
$('#id').val();
If you want to get the data from a element you need to use
1. This will return the text inside the element.
$('#id').text()
2. This will return the html inside the element.
$('#id').html()
Hope it helps you.
Try It...
$("#ObjectsTable").find("tr:gt(0)").remove();
var arr = $.parseJSON(data);
$.each(arr, function(index,value) {
$('#ObjectsTable')
.append($("<tr>" +
"<td>" + value.ID + "</td>" +
"<td>" + value.Model + "</td>" +
"<td>" + value.Type + "</td>" +
"<td>" + value.Color + "</td>" +
"<td>" + value.Price + "</td>" +
"</tr>"));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<table id="ObjectsTable" class="responstable">
<tr>
<th>ID</th>
<th>Model</th>
<th>Type</th>
<th>Color</th>
<th>Price</th>
</tr>
</table>
I'm using mCustomScrollbar to replace the default scrollbars in a div tag containing a table that I draw using javascript to help me reload it when performing ajax calls, here is my HTML code :
<!-- the div that will contain the table-->
<div id="countriesTable" class="customScroll" data-mcs-theme="dark">
</div>
Here is the code of the function that loads the data in the table and draws it inside the div
function reloadTable(data, id) {
var str = '<table class="table"><thead>' +
'<tr><th> Column1 </th>' +
'<th> Column2 </th>' +
'<th> Column3 </th>' +
'<th> Column4 </th></tr></thead><tbody>';
for (var property in data) {
if (data.hasOwnProperty(property)) {
str += '<tr>'
str += '<td>' + data[property][0] + '</td>' +
'<td>' + data[property][1] + '</td>' +
'<td>' + data[property][2] + '</td>' +
'<td>' + data[property][3] + '</td></tr>';
}
}
str += '</tbody></table>';
$(id).html(str);
}
And of course the call of the function to load data and also the function that applies the custom scroll bar effect :
reloadTable(myData, '#countriesTable');
$(".customScroll").mCustomScrollbar();
When the page is loaded the div gets the custom scrollbar successfully, but when I perfom an ajax call to reload data into my table, and I draw it another time using reloadTable function I lose the scrollbar effect.
I've tried to recall the mCustomScrollbar inside the ajax success function but in vain.
I think you need to remove current mCustomScrollbar like this:
$('.customScroll').mCustomScrollbar("destroy")
$('#countriesTable').html("")
reloadTable(myData, '#countriesTable');
$(".customScroll").mCustomScrollbar();
I'm trying to create a dynamic table which will have rows added and removed throughout its use. I do not want to have to put id's on every container that I later want to reference.
For instance, I want to add a hidden input to the last cell of a dynamically added row. The row has an id, how can I use dojo.place() when I do not have an id on the last cell?
var pmrCount = dojo.query("#pmhTable >tbody >tr").length;
var rowID = 'pmr_' + pmrCount;
var newPmrRow =
'<tr id="' + rowID + '">' +
'<td>' + pmh + '</td>' +
'<td>' + String(pmr.severity).charAt(0) + '</td>' +
'<td>' + pmr.customerName + '</td>' +
'<td>' + pmr.deviceType + '</td>' +
'<td>' + pmr.deviceModel + '</td>' +
'<td>' + pmr.deviceSerial + '</td>' +
'<td align="center"><a class="cancel-link"></a></td>' +
'</tr>';
//dojo.place(newPmrRow, dojo.query("#pmhTable >tbody"));
var newPmrHiddenInput =
'<input type="hidden" name="pmrs" value="'+ JSON.stringify(pmr)+ '">';
//dojo.query("#" + rowID + " td:last").place(newPmrHiddenInput);
The two commented lines of code are the ones that I am trying to replace with functional code. These do not work, they don't surface any warnings in the error console like other syntax errors. Not sure where to go from here.
I know that dojo.query() returns a NodeList and place() is expecting an DOM node or an id. What's the correct way to do this?
You want to look at the dojo/NodeList-dom extension to Nodelist. It allows you to place each element in a NodeList into an element based on query selector . In AMD Style it looks like:
require(['dojo/dom-construct', 'dojo/NodeList', 'dojo/NodeList-dom', 'dojo/domReady!'], function (domConstruct, NodeList) {
var nodes = new NodeList([domConstruct.toDom('<div>someContent</div>')]);
nodes.place('#x');
});
Looking at the docs I was kind of surprised there wasn't an easier way to do this, so maybe there is a better way than this.
Well, I found two lines of code that seem to work, but I don't know if referencing NodeLists in an Array style is technically correct for this. This is what I did.
dojo.place(newPmrRow, dojo.query("#pmhTable >tbody")[0]);
dojo.place(newPmrHiddenInput, dojo.query("#" + rowID + "> td:last-child")[0]);