I have a table with an HTML attribute on the TR element titled "data-order" which simply holds an integer indicating the order in which to sort the table (descending). Right now the code only checks the row ahead of the TR clicked - what I'm attempting to do is to get it to scan all rows ahead of its position in the table and once it finds a number greater than (not greater than or equal to) then call the swaprow function...
Here is the javascript used to move the row up.
function adjustRank(id, e) {
var url = "/ajax/moveup/" + aid;
var row = $(e).closest("tr").get(0);
var prevRow = $(row).prev().get(0);
var moveUp = false;
var prevRowOrder = parseInt($(prevRow).attr("data-order"));
var rowOrder = parseInt($(row).attr("data-order"));
$.ajax({
type: "POST",
url: url,
data: {aid: aid},
dataType: "json",
success: function ()
{
if(rowOrder + 1 > prevRowOrder) // think this is where I need to traverse the table
swapRows(row, prevRow);
},
failure: function () { alert("Error processing request."); }
});
}
and here are a couple of items in the table for example:
<table id="listings" style="min-height:150px; width:100%;">
<tr id="1" data-order="11"><td>1</td><td align="left"><span onclick="adjustRank('ace93485-cea5-4243-8294-9f3d009aba3d', this)" style="cursor:pointer;">Lindsey Vonn</span></td><td></td></tr>
<tr id="2" data-order="6"><td>2</td><td align="left"><span onclick="adjustRank('9f83aed6-b99a-4674-a8b7-9f3d009aba38', this)" style="cursor:pointer;">Al Horford</span></td><td></td></tr>
<tr id="3" data-order="5"><td>3</td><td align="left"><span onclick="adjustRank('d48a52bd-17e9-4631-9a2e-9f3d009aba39', this)" style="cursor:pointer;">Derek Jeter</span></td><td></td></tr>
</table>
You may use recursion to solve that problem. Please, see the code.
window.adjustRank = function(id, el) {
var orderDiff = 1;
var row = $(el).closest("tr");
var order = parseInt(row.attr("data-order")) + orderDiff;
row.attr("data-order", order);
var prevRow = row.prev();
if(prevRow.get(0)){
moveUp(order, row, prevRow);
}
}
window.moveUp = function(order, row, prevRow){
if(order > parseInt(prevRow.attr("data-order"))){
var prevPrevRow = prevRow.prev();
if(prevPrevRow.get(0)){
moveUp(order, row, prevPrevRow);
} else {
prevRow.before(row);
}
} else {
prevRow.after(row);
}
}
If you get orderDiff via AJAX, then place the code into your AJAX call success function. Please, see this demo
Related
<script type="text/javascript">
function LoadData(){
var url = serverURL+"/List.php";
$.ajax({
type: "GET",
url: url,
dataType: "json",
success: function(data){
$.each(data.data, function (key, value) {
var doc_id=value['id'];
var doc_name=value['name'];
var doc_speci = value['specialize'];
$("#myTable").append("<tr><td>"+doc_name+"</td><td>"+doc_speci+"</td><td class='retrieve' data-did="+doc_id+" style='cursor: pointer;'>EDIT</td></tr>");
});
},
error: function(data){
toastr.error("Opps! Something went wrong");
$(".se-pre-con").fadeOut("slow");
},
});
}
</script>
The above appends a tr to my html table below.
The HTML TABLE is as follows:
<table id="myTable" class='table table-bordered table-hover table-striped'>
<tr>
<th>Name</th>
<th>Specialization</th>
<th>Action</th>
</tr>
</table>
Now i want to retrieve the id from the data attribute from td class retrieve so that i can send the id and redirect it to other page for editing.
// Clicks the edit field
$("td.retrieve").on("click", function(e) {
var id = $(e.currentTarget).attr("data-did");
// do with the ID what you want
alert(id);
});
I'm aware that jQuery has a "data(...)" function but I've run into issues with that sometimes in the past. "attr(...)" will do something similar but relies specifically on the attribute instead of stored objects.
First, to add your data attribute you should make sure you add quotes around the value:
data-did='"+doc_id+"'...
So the rendered cell must look something like this:
<td class='retrieve' data-did='n' style='cursor: pointer;'>EDIT</td>
(where n is some value)
Then you can easily retrieve this value with jQuery:
$('specific-td').data('did'); //specific-td referes to a specific cell in a row, you must write that, this is just an example
To get all of the rows:
var ids = [];
$('.retrieve').each(function() {
ids.push($(this).data('did'));
});
Example:
If you have a button for example:
$('#myTable').on('click', '.retrieve input[type="button"]', function() {
var id = $(this).parent().data('did');
alert(id);
});
JSFiddle: https://jsfiddle.net/y2an0fu7/1/
Here is my jsfiddle work. I have some issues with generating table without any html. I have one json object that i need to itterate and to put keys and values in table like:
<tr> <td> key </td> <td> key </td> ... </tr>
<tr> <td> val </td> <td> val </td> ... </tr>
I tried first to generate the table like this one, but next i wanted to use jquery version of creating td's and tr's, but the all keys and values were appended in only one td and actually this is not what i want.
You have to loop through keys the first time to set the head of table, after that make the rows inside each and append every one to the table to make the body of your table, check example code bellow :
$.ajax({
type : "POST",
dataType : "json",
url : '/echo/json/',
data : { json: JSON.stringify( jsonData ) },
success : function(data){
var jsn = $(data.markers);
//First time append table head
if(!header)
{
var row = $('<tr></tr>');
for(key in jsn[0])
{
row.append('<th>'+key+'</th>');
}
table.append(row);
header = true;
}
for ( var i = 0; i < jsn.length ; i++){
var row = $('<tr></tr>');
$.each(jsn[i], function(key,val)
{
row.append('<td>'+val+'</td>');
});
table.append(row);
}
}
});
Take a look at Working fiddle.
Hope this helps.
The issue was in the scope of the col and row variables. You must reassign them in the loop, or redeclare.
Here is the updated jsfiddle. By the way there is no need to use for loop. In jQuery it is enough to use the $.each function on the object.
From here you can see how to create table structure and replace the key and val with the actual data you need.
You need to create new row object in each for iteration:
for (var mrksIndex = 0, mrksLength = jsn.length; mrksIndex <= mrksLength; ++mrksIndex) {
row = $("<tr/>");
$.each(jsn[mrksIndex], function (key, val) {
col = $("<td/>");
col.append(key);
row.append(col);
table.append(row);
});
}
Demo: https://jsfiddle.net/6dw2u8uz/15/
The table with the knockout.js bindings currenlty looks lke this:
source total division
00234 4506 div1
30222 456 div2
63321 23 div2
40941 189 div1
The desired output would be something like below. The data needs to grouped by division.
source total
div1
00234 4506
40941 189
div2
30222 456
63321 23
Here's my ViewModel:
var ReportingViewModel;
ReportingViewModel = { Results: ko.observableArray(null) }
The ReportingViewModel gets populated via an ajax request:
ReportingViewModel.Results(data["Data"]["Report"]);
Q: How can I achieve the desired output?
EDIT:
Here's my View:
<table class="table table-condensed" id="reportData">
<thead>
<tr>
<th>source</th>
<th>total</th>
<th>division</th>
</tr>
</thead>
<tbody data-bind="foreach: Results">
<tr>
<td data-bind="text: source"></td>
<td data-bind="text: total"></td>
<td data-bind="text: division"></td>
</tr>
</tbody>
</table>
<script type="text/javascript">
$(document).ready(function () {
ReportingViewModel.Results(null);
e.preventDefault();
var numbers = null;
if ($('#numbersdd').find("option:selected").length > 0) {
numbers = $('#numbersdd').find("option:selected");}
if (numbers != null) {
$.ajax({
url: '/Reporting/ReportData.aspx',
type: 'POST',
data: numbers,
dataType: 'json',
contentType: "application/json",
success: function (data) {
ReportingViewModel.Results(data["Data"]["Report"]);
},
error: function () {
alert('Error Running Report');
}
});
}
else { alert('No Data!'); }
});
var ReportingViewModel;
ReportingViewModel = {
Results: ko.observableArray(null),
}
ko.applyBindings(ReportingViewModel);
});
</script>
You may declare computed field like this:
GroupedResults: ko.computed(function() {
var result = {};
var original = ReportingViewModel.Results();
for (var i = 0; i < original.length; i++) {
var item = original[i];
result[item.division] = result[item.division] || [];
result[item.division].push(item);
}
return result;
})
This computed field will return object like this:
{
div1: [{source: 234, total: 4506, division: 'div1'}]
div2: [{source: 30222, total: 456, division: 'div2'}]
}
As you can see each property is a division and it contains array of records which are related to this division.
Then just bind your view to this new computed field.
If you want to create your computed as part of your ReportingViewModel declaration, do it like this:
var ReportingViewModel = function(data) {
var self = this;
self.Results = ko.observableArray(data);
self.GroupedResults = ko.computed(...)
}
Then your invocation of the object is similar to how you currently have it...but not.
var reportingViewModel = new ReportingViewModel(data["Data"]["Report"]);
ko.applyBindings(reportingViewModel);
Here is a reasonable fiddle on grouping data in Knockout 2.0 that should work for you.
http://jsfiddle.net/rniemeyer/mXVtN/
Most importantly, you should be transforming your data so you have your divisions as an element to loop through and each division has a computed child that returns the matching data. He happens to use an extension on the observableArray property itself to manage this...
ko.observableArray.fn.distinct = function(prop) {
var target = this;
target.index = {};
target.index[prop] = ko.observable({});
ko.computed(function() {
//rebuild index
var propIndex = {};
ko.utils.arrayForEach(target(), function(item) {
var key = ko.utils.unwrapObservable(item[prop]);
if (key) {
propIndex[key] = propIndex[key] || [];
propIndex[key].push(item);
}
});
target.index[prop](propIndex);
});
return target;
};
Then in your markup just data-bind to loop through your divisions.
Im trying to remove rows from a table that match 2 values ie using and AND operator to match where user = username and phrase = searchedphrase
So for example:
<table>
<tr class="user1">
<td class="user">user1</td>
<td class="phrase">phrase1</td>
<td class="filename">filename1</td>
<td><button class="blacklist" data-value="user1" data-phrase="phrase1">Blacklist</button></td></tr>
<tr class="user1">
<td class="user">user1</td>
<td class="phrase">phrase2</td>
<td class="filename">filename2</td>
<td><button class="blacklist" data-value="user1" data-phrase="phrase2">Blacklist</button></td></tr>
<tr class="user1">
<td class="user">user1</td>
<td class="phrase">phrase1</td>
<td class="filename">filename3</td>
<td><button class="blacklist" data-value="user1" data-phrase="phrase1">Blacklist</button></td></tr>
I've used data- in the button elements to pass values to an ajax script that executes some php, i suspect this may not be an optimal way of doing things im very new to jquery.
I can identify multiple rows and manipulate them using
$('.'+user).css("background-color","red");
I guess i need a function to pull out the rows matching both values and iterate them over .remove?
This is how the script is triggered, any pointers on the best way to do this would be greatly appreciated!
<script type="text/javascript">
$('.blacklist').click(function()
{
var user = $(this).data('value');
var phrase = $(this).data('phrase');
if(user != '')
{
$.ajax({
url: 'test.php',
method: 'POST',
dataType:'json',
data: {'user' : user}, //then getting $_POST['user']
success: function(data)
{
}
If you wanted to do this all within your jquery function, it'd look something like:
$('.blacklist').click(function()
{
var user = $(this).data('value');
var phrase = $(this).data('phrase');
if (user != '')
{
//loop through each row of the table
$('table tr').each(function()
{
//check if criteria matches
if ($(this).find('.user').html() == user && $(this).find('.phrase').html() == phrase)
{
//remove the row
$(this).remove();
//if you needed to use ajax to perform some kind of DB operation
//you could perform this here as well
/*
$.ajax({
url: 'test.php',
method: 'POST',
dataType:'json',
data: {'user' : user}, //then getting $_POST['user']
success: function(data)
{
}
});
*/
}
});
}
});
You can use filter() to create element collections that aren't easily accomplished using selectors.
Assume you want to run some conditional checks on the text in your td.user and td.phrase classes you can do something like.
var userMatch= /* some value */
var phraseMatch = /* some other value */
$('tr.user').filter(function(){
var user= $(this).find('.user').text(), phrase=$(this).find('.phrase').text();
/* return boolean based on conditions desired*/
return user === userMatch && phrase === phraseMatch;
/* remove the new collection returned by "filter" */
}).remove();
filter() API Docs
I've just thought of a way to do this with php - I can create an md5 hash of the user and phrase then assign it to a data-hash value. This would enable me to use something like
var hash = $(this).data('hash');
$('.'+hash).remove();
I have some razor syntax which is dynamically generating an html table and populating with data while generating it. I needed to make a jQuery ajax call to my MVC ASP.Net controller to get some data to go in another field in this exact table. Now what I was trying to do is to iterate through the child nodes of this table and append this field cell by cell in these rows after it loads.
However this is not being successful, the table is showing as if it doesn't have any child nodes i.e. the razor syntax is not done executing by that time.
What can I do so that this script for adding the extra field is executed after the html table has been filled up with data? This is the code I have. This is the razor and html syntax.
#if (Model.ToList().Count > 0) {
<table id ="groupTable">
<thead>
<tr>
<th>Group Name</th>
<th>Description</th>
</tr>
</thead>
<tbody id="innerTable">
#foreach (var group in Model) {
// display a link with each GroupName as a list which directs to that group with that id
<tr>
<td> #Html.ActionLink(group.Group.GroupName,"DisplayGroup","Groups", new {id = group.GroupId},null) </td>
<td>
#if(group.Group.Description.Length > 40){
#group.Group.Description.Substring(0, 40)
<span>...</span>
}
else
{
#group.Group.Description.Substring(0, group.Group.Description.Length - 1)
}
</td>
</tr>
}
</tbody>
</table>
}
And this is the script executed on document.ready
$(document).ready( function() {
#foreach (var group in Model)
{
<text>
jQuery.ajax({
type: 'POST',
url: '/Groups/GetInvitedFriends',
data: { groupId: '#group.Group.GroupId' },
success: function (friendMembers) {
$.each(friendMembers, function (index, friendName) {
// append friend Members at row with index index at that cell
var tbody = $('#innerTable')[0];
var trow = tbody.childNodes[index];
if (trow.index() === 0) {
trow.append('<td> Members </td>');
} else {
trow.append('<td>' + friendName + '</td>');
}
});
},
traditional: true
});
</text>
}
})
As the javascript will only be executed on the client browser, you can store the group's id in an javascript array and then in document load, loop on this array to add each of your extra cells.
This is the javascript code :
<script type="text/javascript">
//List of groups id
var groupIds = [];
$(function() {
//Initializing the array with values
#foreach (var group in Model) {
<text>groupIds .push(#group.Group.GroupId);</text>
}
InsertExtraCells(groupIds.pop()); //Insert for the first groupid in the array
});
function InsertExtraCells(groupId) {
jQuery.ajax({
type: 'POST',
url: '/Groups/GetInvitedFriends',
data: { groupId: '#group.Group.GroupId' },
success: function (friendMembers) {
//Do your work
$.each(friendMembers, function (index, friendName) {
// append friend Members at row with index index at that cell
var tbody = $('#innerTable')[0];
var trow = tbody.childNodes[index];
if (trow.index() === 0) {
trow.append('<td> Members </td>');
} else {
trow.append('<td>' + friendName + '</td>');
}
});
//If ids remaining in the array, loop to the next group id
if (groupIds.length > 0) {
InsertExtraCells(groupIds.pop());
}
else {
//Do whatever when finish
}
},
traditional: true
});
}
</script>