I have a snippet I've developed to increase the size of an image and take the td to the right of the image and drop it beneath.
However - it's taking a good few seconds, from the time it takes to remove the TD to add it in, and it makes the page rendering/paint/flow look terrible.
Please see the video below for a better understanding of what is happening.
http://screencast.com/t/RQdBiNyGkEm
Please also see my code snippet below;
<script>
$(document).ready(function() {
$('html').addClass('js');
$('.description').show();
// add a td for initial page load of cart.
$("table#shopping-cart-items tr td.image").after($('<td id="clearSpacePageLoad"></td>'));
// take content from right - and drop it beneath the image
$('#shopping-cart-items > tbody > tr').each(function() {
var desc = $('td.description', this).html()
$('td.description', this).remove();
$('td.image', this).append(desc);
});
});
</script>
<script>
//When selecting a delivery method - everything resets due to AJAX.
$(document).ready(function() {
// Use .live() in stead of .on() since jQuery is < 1.9
// On select of delivery method do the following
$('.shippingOpt').live('click', function() {
// Wait for ALL ajax requests on page (Past and future) to execute BEFORE executing the following
$(document).ajaxStop(function() {
// Repeat the same code as initial page load.
$('img.item-img').each(function() {
var str = $(this).attr('src'),
arr = str.split("?");
query = "?hei=200&wid=200&op_sharpen=1"
$(this).attr('src', arr[0] + query);
});
$('#shopping-cart-items > tbody > tr').each(function() {
var desc = $('td.description', this).html()
$('td.image', this).append(desc);
$('td.description', this).remove();
});
// If ID of 'clearSpaceOnClick' exists don't add another td, if it doesn't - add it!
if ($('#clearSpaceOnClick').length) {} else {
$("table#shopping-cart-items tr td.image").after($('<td id="clearSpaceOnClick"></td>'));
}
});
});
});
</script>
<style>
.checkoutBasket table.cart-container td.image img {
width: 200px;
height: auto;
}
#clearSpace {
padding: 0 0 0 15px;
}
</style>
From looking at the video, you are almost certainly injecting an additional td element and now there are more tds on the row than there are columns in your table. You should be able to see an issue if you inspect element.
Off hand, I would look very closely at the logic related to the line below but you dont give us your html so we cant know for sure:
$("table#shopping-cart-items tr td.image").after($('<td id="clearSpaceOnClick"></td>'));
If there are multiple td.image in table#shopping-cart-items then you should not append an element with an ID (as ID's must be unique), which you're doing in 2 places in your code.
It looks like you might be selecting an (already active) shipping option. In that case ajaxstop may be delaying things if there are any outstanding ajax requests.
Also, jQuery .on has been available since v1.7, not 1.9
Related
I have an table in my HTMl view (php mvc).
The table displays some basic information in a row.
By clicking the 'More' botton (+) you can see other information belonging to this user.
But somehow activating the JS chances the width of the affected row and the rows below, and slightly the first row.
How is this possible? And how can I prevent this?
Any help is welcome.
The code is in a fiddle here https://jsfiddle.net/jdkosnl/e71ms5ar/41/
$(document).ready(function () {
$('.show-more-button').click(function () {
var $this = $(this);
var forId = $(this).data('more-for');
var $showMoreElement = $(this).closest('table').children('.show-more[data-more-id="' + forId + '"]');
if ($this.hasClass('fa-plus-square')) {
$this.removeClass('fa-plus-square').addClass('fa-minus-square');
$showMoreElement.css('display', 'block');
} else if ($this.hasClass('fa-minus-square')) {
$this.removeClass('fa-minus-square').addClass('fa-plus-square');
$showMoreElement.css('display', 'none');
}
});
});
Try to avoid using display: block when working with tables and their elements. The suitable value for tbody is 'table-row-group' (instead of 'block'). Like this:
if ($this.hasClass('fa-plus-square')) {
$this.removeClass('fa-plus-square').addClass('fa-minus-square');
$showMoreElement.css('display', 'table-row-group');
}
JSFiddle.
The problem I am encountering, is that I have to many duplicates. I am basically trying to show 1/11 tables by which bottom is clicked (list_row[1-11]), so when I show for instance table 2, it must hide all the other tables.
I believe this can be shortened by a loop or something else, because if I have 100 tables then I must copy and paste, not smart. Keep in mind that the code below is just showing table 1 to table 3. How can I prevent these duplicates?
// hide the tables by default when page loads
$('#table1').hide();
$('#table2').hide();
$('#table3').hide();
$('#table4').hide();
$('#table5').hide();
$('#table6').hide();
$('#table7').hide();
$('#table8').hide();
$('#table9').hide();
$('#table10').hide();
$('#table11').hide();
// Show Exhaust Temperature diagram
$('#list_row1').on('click',function(){
$('#table1').show();
$('#table2').hide();
$('#table3').hide();
$('#table4').hide();
$('#table5').hide();
$('#table6').hide();
$('#table7').hide();
$('#table8').hide();
$('#table9').hide();
$('#table10').hide();
$('#table11').hide();
});
// Show Cylinder Pressure diagram
$('#list_row2').on('click',function(){
$('#table1').hide();
$('#table2').show();
$('#table3').hide();
$('#table4').hide();
$('#table5').hide();
$('#table6').hide();
$('#table7').hide();
$('#table8').hide();
$('#table9').hide();
$('#table10').hide();
$('#table11').hide();
});
$('#list_row3').on('click',function(){
$('#table1').hide();
$('#table2').hide();
$('#table3').show();
$('#table4').hide();
$('#table5').hide();
$('#table6').hide();
$('#table7').hide();
$('#table8').hide();
$('#table9').hide();
$('#table10').hide();
$('#table11').hide();
});
// Code continues to table11.
Set all your tables to display: none then introduce an .active class set to display: block (or display: table, in this case). Then simply toggle the class on and off:
.active {
display: table;
}
$('#list_row1').on('click', function() {
$('.active').removeClass('active');
$('#table1').addClass('active');
});
To avoid repetition, however, you'd be better off extending this this to add data-* attributes to your #list_row/n/ elements, and handle click events on these:
<elem id="list_row1" data-row="1"></elem>
$('[data-row]').on('click', function() {
var row = $(this).attr('data-row');
$('.active').removeClass('active');
$('#table' + row).addClass('active');
});
Do also note that you can chain selectors with commas. Rather than using $(elem1).hide(); $(elem2).hide() you can instead $(elem1, elem2).hide().
Try
$('[id^=list_row]').on('click',function(){
$('table').hide();
$('#table'+$(this).attr('id').slice(8)).show();
});
You can also use the starts-with jQuery selector:
$('id^="table"').hide();
$('id^="list_row"').on('click',function(){
var num = this.id.split('w')[1]; //alert(num)
$('id^="table"').hide();
$('#table'+num).show();
});
Reference:
All jQuery Selectors
Add a class to all your table and listrow elements, and a custom attribute on those lasts to identify where are you clicking.
<table id="table2" class="tableClass">
<whatever id="list_row2" class="listRowClass" data-yourProjectname-numRow="2">
This way you can just show the table that's been clicked and hide all the rest:
$(".listRowClass").on("click", function() {
$(".tableClass").hide() // Hides all tables
$("#table" + $(this).attr("data-yourProjectname-numRow")).show() //Shows clicked table
});
(jQuery noob here)
Im trying to write a script which when I write <input type='checkbox'/> will automatically convert it to jQuery UI button and look like a checkBox.
Sample code so far ...
var newCheckboxID = 0;
$( "input:checkbox" ).attr('id', "cbx-" + nextCheckboxID++); // how to do that?
$( "input:checkbox" ).after("<label style='width:16px; height:16px; vertical-align:middle;'></label>");
$( "input:checkbox" ).next().attr("for", $(this).attr('id') ); // doesn't work for sure
$( "input:checkbox" ).button();
$( "input:checkbox" ).button( "option", "text", false );
$( "input:checkbox" ).attr("onclick", "$(this).button( 'option', 'icons', {primary:((this.checked)?'ui-icon-check':null),secondary:null} )");
Sorry, if it's too obvious but I've lost more than hour in that ...
EDIT
Finally did it with the old fashioned way (for the doesn't working parts).
Any comments for making it more compact and "more jQuery" would be appriciated ...
Code sample
// ---- set ids
var checkboxID = 0;
//$( "input:checkbox" ).attr('id', "cbx-" + nextCheckboxID++); // how to do that?
var cboxes = document.getElementsByTagName('input'); // <-- do this instead
for(var i=0; i<cboxes.length; i++){
if( cboxes[i].getAttribute('type')!='checkbox' ) continue;
cboxes[i].setAttribute('id', 'cbx-'+checkboxID++);}
// ---- add labels
$( "input:checkbox" ).after("<label style='width:16px; height:16px; vertical-align:middle;'></label>");
//$( "input:checkbox" ).next().attr("for", $(this).attr('id') ); // doesn't work this
for(var i=0; i<cboxes.length; i++){ // <-- do this instead
if( cboxes[i].getAttribute('type')!='checkbox' ) continue;
cboxes[i].nextSibling.setAttribute('for', cboxes[i].getAttribute('id') );}
// ---- create
$( "input:checkbox" ).button();
$( "input:checkbox" ).button( "option", "text", false );
$( "input:checkbox" ).attr("onclick", "$(this).button( 'option', 'icons', {primary:((this.checked)?'ui-icon-check':null),secondary:null} )");
Working examples:
jsFiddle (without comments)
jsFiddle (without comments with UI theme switcher!)
jsFiddle (with comments)
jsFiddle (Just for fun, uses timer and some other jQuery features, just for future reference)
jsFiddle (Just for fun, uses timer and changes UI theme every second!)
In the following, I should note 2 primary changes. I added CSS to do what you were trying to do to labels in "code" (where it really doesn't belong).
Also, I changed the HTML for "ease of jQuery" use. However, I still noted in the comments how you can easily change it back.
the HTML
<center>
<button>Create New CheckBox</button>
</center>
<hr />
<div id="CheckBoxes">
<input class="inp-checkbox" />
<input class="inp-checkbox" />
<input class="inp-checkbox" />
<input class="inp-checkbox" />
</div>
the CSS
.inp-checkbox+label {
width:16px;
height:16px;
vertical-align:middle;
}
the JavaScript/jQuery
// keep in mind, and i will explain, some of these "moving-parts" or not needed, but are added to show you the "ease" of jquery and help you see the solution
// This global function is designed simply to allow the creation of new checkboxes as you specified, however, if you won't be making check boxes at end user time, then i suggest simply moving it to within the .each statement found later on.
// Also, this could easily be written as a jQuery plugin so that you could make a "chainable" one-line call to change checkboxes to this but let's get to the nitty gritty first
function createCheckBox(ele, i) {
// First I simply create the new ID here, of course you can do this inline, but this gives us a bottleneck for possible errors
var newID = "cbx-"+i;
// below we use the param "ele" wich will be a jQuery Element object like $("#eleID")
// This gives us the "chainability" we want so we don't need to waste time writing more lines to recall our element
// You will also notice, the first thing i do is asign the "attribute" ID
ele.attr({ "id": newID })
// Here we see "chainability at work, by not closing the last line, we can move right on to the next bit of code to apply to our element
// In this case, I'm changing a "property", keep in mind this is kinda new to jQuery,
// In older versions, you would have used .attr but now jQuery distinguishes between "attributes" and "properties" on elements (note we are using "edge", aka. the latest jQuery version
.prop({ "type": "checkbox" })
// .after allows us to add an element after, but maintain our chainability so that we can continue to work on the input
// here of course, I create a NEW label and then immidiatly add its "for" attribute to relate to our input ID
.after($("<label />").attr({ for: newID }))
// I should note, by changing your CSS and/or changing input to <button>, you can ELIMINATE the previous step all together
// Now that the new label is added, lets set our input to be a button,
.button({ text: false }) // of course, icon only
// finally, let's add that click function and move on!
// again, notice jQuery's chainability allows us no need to recall our element
.click(function(e) {
// FYI, there are about a dozen ways to achieve this, but for now, I'll stick with your example as it's not far from correct
var toConsole = $(this).button("option", {
icons: {
primary: $(this)[0].checked ? "ui-icon-check" : ""
}
});
console.log(toConsole, toConsole[0].checked);
});
// Finally, for sake of consoling this new button creation and showing you how it works, I'll return our ORIGINAL (yet now changed) element
return ele;
}
$(function() {
// This .each call upon the inputs containing the class I asiged them in the html,
// Allows an easy way to edit each input and maintain a counter variable
// Thus the "i" parameter
// You could also use your ORIGINAL HTML, just change $(".inp-checkbox") to $("input:[type='checkbox']") or even $("input:checkbox")
$(".inp-checkbox").each(function(i) {
// as previously noted, we asign this function to a variable in order to get the return and console log it for your future vision!
var newCheckBox = createCheckBox($(this), i);
console.log(newCheckBox);
});
// This next button added is simply to show how you can add new buttons at end-time
// ENJOY!!!
$("button").button().on("click", function(e) {
var checkBoxCount = $("#CheckBoxes .inp-checkbox").length;
var newCheckBox = $("<input />").addClass("inp-checkbox").appendTo($("#CheckBoxes"));
createCheckBox(newCheckBox , checkBoxCount);
console.log(newCheckBox);
});
});
Update: The original intent here was to purely answer the question, which was to create a jQuery UI styled checkbox and show how jQuery can be used in multiple ways. However, a later comment queried how to include a traditional style label with it. While there are a billion options for this, I'll simply take from the above and extend.
The first option I took is pretty simple. Using jsFiddle (without comments with UI theme switcher!), I made the following changes:
the JavaScript/jQuery
// First I add a new variable.
// It will simply be for a new "wrapper" element, in which to ensure our button is encased.
// Giving this element a new class gives easy access for later CSS or Event Triggering of sub elements (like the checkbox)
var newID = "cbx-"+i,
wrapper = $('<div />', { 'class': 'ui-checkbox-wrapper' }).appendTo('#CheckBoxes');
// Then I added a line to our ele series of methods.
// This line simply append our element (checkbox) to our new wrapper
// Take Note at how I added this method at start rather than at end.
// Had I not done this, then the label would not have been wrapped!
ele.appendTo(wrapper) // <-- new line!
.attr({ "id": newID })
Then I simply added the following CSS:
#CheckBoxes .ui-button .ui-button-text {
background: #A9A9A9;
display: inline;
font-size: 16px;
left: 19px;
padding: 0;
position: relative;
text-indent: 0;
top: -4px;
}
Results!
I have the following example http://jsfiddle.net/zidski/MxqRu/1/
When you click on 2010 I need valuation to disappear with the list items.
Here is the code which I am using to do this:
$("#yearfilter a").live("click", function(e) {
e.preventDefault();
//var v = $(this).val();
var v = $(this).attr("data-value");
if(v.length > 0) {
$('tr.reports').show();
$('tr.reports ul').hide();
$('tr.reports ul.year-'+v).show();
$('tr.reports').each(function() {
if($('ul:visible', this).size() == 0) {
$(this).hide();
}
});
} else {
$('tr.reports').show();
$('tr.reports ul').show();
}
});
I have done it in my project something like this:
function toggleRow(row_id) {
row_selector = "#row_" + row_id;
$(row_selector).toggleClass("shown hidden")
}
Then in the CSS:
.hidden {display:none;}
.shown {}
Then in the HTML I have alternating table rows, where the odd rows act as headings for the content in the even rows. Clicking an odd row toggles the visibility of the corresponding even row.
...
<tr onclick="toggleRow(17)">...</tr>
<tr class="hidden" id="row_17">...</tr>
...
Give each tr an ID something like id="row_2010" then look for that and hide the whole entire row at once.
UPDATE
I would strongly suggest not using so many tables and use more classes to classify your data structure. It would help your javascript be much more clean, concise and function easier.
UPDATE
I adjusted all your javacsript and some of your html. Here is a fully working example jsFiddle Demo
I have a 5×7 HTML table. On many queries, there are fewer than 35 items filling the complete table.
How can I "hide" the empty cells dynamically in this case, using jQuery (or any other efficient way)?
Edit - Improved Version
// Grab every row in your table
$('table#yourTable tr').each(function(){
if($(this).children('td:empty').length === $(this).children('td').length){
$(this).remove(); // or $(this).hide();
}
});
Not tested but seems logically sound.
// Grab every row in your table
$('table#yourTable tr').each(function(){
var isEmpty = true;
// Process every column
$(this).children('td').each(function(){
// If data is present inside of a given column let the row know
if($.trim($(this).html()) !== '') {
isEmpty = false;
// We stop after proving that at least one column in a row has data
return false;
}
});
// If the whole row is empty remove it from the dom
if(isEmpty) $(this).remove();
});
Obviously you'll want to adjust the selector to fit your specific needs:
$('td').each(function(){
if ($(this).html() == '') {
$(this).hide();
}
});
$('td:empty').hide();
How about CSS empty-cells
table {
empty-cells: hide;
}
I'm voting for Ballsacian's answer. For some reason,
$('table#myTable tr:not(:has(td:not(:empty)))').hide();
has a bug. If you remove the outermost :not(), it does what you'd expect, but the full expression above crashes jQuery.