Trying to get width of element inside .each() - javascript

I am trying to get the width of an element whilst inside a .each() function however I am running into issues with it simply not working.
jQuery(document).ready(function($) {
$('.tooltip').each(function() {
var self = $(this);
var width = self.find("#testing").offsetWidth;
alert(width); //Returns undefined
$(this).find(".tooltip-icon").hover(function(){
self.find(".tooltip-text").show();
}, function () {
self.find(".tooltip-text").hide();
});
});
});

you are using jquery and javascript in the same line
do this
var width = self.find("#testing").width(); // jquery. you should change the name of the `self` variable to another one

Related

Storing variable via .text() isn't uptodate

I have <span> tags in a div that is removed when user clicks on them. Works fine.
I want to store the .text() inside that div in a variable. The problem is that the updated text doesn't get stored.
Click on a word to remove it in this jsFiddle.
As you can see, the content variable returns the old text, not the new revised one.
How can I store a variable with the updated text?
jQuery:
jQuery(document).ready(function() {
jQuery(document).on("mousedown", ".hello span", function() {
// don't add full stop at the end of sentence if it already ends with
var endChars = [".", "?", "!"];
jQuery(this).fadeOut(function(){
var parentObj = jQuery(this).parent();
jQuery(this).remove();
var text = parentObj.find("span").first().html();
parentObj.find("span").first().html(ta_capitalizeFirstLetter(text));
text = parentObj.find("span").last().html();
if ( endChars.indexOf(text.slice(-1)) == -1 )
{
parentObj.find("span").last().html(text+".");
}
});
var content = jQuery(this).parent().parent().find('.hello').text();
alert(content);
});
});
The code to get the new text should be moved inside the fadeOut callback. Once the animation is completed and element is removed, then the innerText of the parent element will be updated. At this time, the updated content should be read from the DOM.
Demo
// Cache the element
var $el = jQuery(this).parent().parent().find('.hello');
jQuery(this).fadeOut(function () {
jQuery(this).remove();
// Irrelevant code removed from here
...
var content = $el.text();
alert(content);
});
Here's another simple demo with minimal code that'll help to understand the code better.
Demo
I tried to debug your jsfiddle in chrome, and it looks like the priority of your code is like this:
declare on this event - jQuery(this).fadeOut(function(){
get the the current data of the div var content = jQuery(this).parent().parent().find('.hello').text();.
alert your data without changes.
calling the funcntion of fadeout
I think all you have to do is to call your alert and 2 from your anonymous function of fadeout
Just put your alert inside the callback:
jQuery(this).fadeOut(function(){
var parentObj = jQuery(this).parent();
jQuery(this).remove();
var text = parentObj.find("span").first().html();
parentObj.find("span").first().html(ta_capitalizeFirstLetter(text));
text = parentObj.find("span").last().html();
if ( endChars.indexOf(text.slice(-1)) == -1 ) {
parentObj.find("span").last().html(text+".");
var content = parentObj.parent().find('.hello').text();
alert(content);
}
});

JavaScript global array undefined although it shows in alert

I have written a JQuery script in SharePoint to truncate a multiple lines of text column. Below is the script:
<script>
window.$divs = [];
window.$i = 0;
window.textFull = new Array();
$(document).ready(function(){
window.setInterval(function(){
/// call your function here
$divs = $("[class^=ExternalClass]");
for($i=0;$i<$divs.length;$i++)
{
textFull[$i] = $($divs[$i]).html();
if(typeof textFull[$i] != 'undefined' && textFull[$i].length > 50)
{
//alert($textFull[$i]); this alert show the correct text
$($divs[$i]).html(textFull[$i].substring(0,49)+"<a href='javascript:alert(textFull[$i]);'>...more</a>");
}
}
}, 500);
});
</script>​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
In the above code "javascript:alert(textFull[$i])" shows 'undefined' in alert. But the alert above it shows correct text. Also I when I use a variable instead of an array it works fine in the alert inside anchor tag. I have also declared the array as global. So what am I missing?
You are running into the classic problem using for loop without using a closure to keep track of the index with
No need to create that array if all it is used for is to modify the html
Can do that much simpler using html(fn) and a jQuery event handler
$("[class^=ExternalClass]").html(function(index, oldhtml){
if(oldhtml.length >=50){
// store the full html in element data
$(this).data('html', oldhtml)
return oldhtml.substring(0,49)+"<a class="more-btn">...more</a>"
} else{
return oldhtml
}
}).find('.more-btn').click(function(){
var $div = $(this).parent();
$div.html( $div.data('html'));
});

Combining Similar If Statements In Javascript

I'm using JS with similar if statements in order to have Divs side by side. As the topic title suggests, can these if statements be combined or made more efficient in any way?
EDIT: The purpose of this code is to make all Divs the same height.
JS:
$(document).ready(function(){
$('.container').each(function(){
var firstDiv = $(this).find('.first');
var secondDiv = $(this).find('.second');
var thirdDiv = $(this).find('.third');
var fourthDiv = $(this).find('.fourth');
if(firstDiv.height() >= secondDiv.height()){
secondDiv.css('height',firstDiv.height());
} else {
firstDiv.css('height',secondDiv.height());
}
if(secondDiv.height() >= thirdDiv.height()){
thirdDiv.css('height',secondDiv.height());
} else {
secondDiv.css('height',thirdDiv.height());
}
if(thirdDiv.height() >= fourthDiv.height()){
fourthDiv.css('height',thirdDiv.height());
} else {
thirdDiv.css('height',fourthDiv.height());
}
});
});
Test page: http://www.gloryhood.com/articles/ztest.html
As the intention of the code is to equalise the heights of all the divs, you can negate the need for any if statements and use jQuery's map() to get all the heights, then use Math.max to get the tallest. Try this:
$('.container').each(function(){
var $divs = $('.first, .seconds, .third, .fourth', this);
var heights = $divs.map(function() {
return $(this).height();
}).get();
$divs.height(Math.max.apply(this, heights));
});
Note that the initial selector could be improved by adding a single common class to all the divs.
If your aim is to make all the heights the max height of any, the current code will not work (unless the first div is tallest).
Solution: check the heights for the max height first, then apply that height to them all.
$(document).ready(function () {
$('.container').each(function () {
var $divs = $('.blah', this);
var height = 0;
$divs.each(function(){
height = Math.max($(this).height(), height);
});
$divs.css('height',height);
});
});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/8hko6of7/1/
Notes
I do not use your class names, but instead a common class on all the divs.
If your aim was something else, please explain in more detail :)

animation function is not applied to each elements

here is a problem i am facing in my progressbar. i have data-percent attribute in my "pro-bar" class . each data-percent is different but when in browser i'am getting first pro-bar's data-percent value applied to all
Here is my code:
$('.pro-bar').each(function( i, elem ){
var percent = $('.pro-bar').attr('data-percent'),
barparcent = Math.round(percent*5.56),
$elem = $(this);
console.log(percent);
$elem.animate({'width':barparcent}, 2000, 'easeInOutExpo');
});
Your problem is how you are referring to your pro-bar inside the each. Use "this" to refer to the current element, not a general class selector.
$('.pro-bar').each(function( i, elem ){
var percent = $(this).attr('data-percent'),//change here
barparcent = Math.round(percent*5.56),
$elem = $(this);
console.log(percent);
$elem.animate({'width':barparcent}, 2000, 'easeInOutExpo');
});
Further explanation:
$(".pro-bar").attr("data-percent") gets all of the .pro-bar, then .attr("data-percent") gets the value of the first element (as does most other similar jquery methods). Then as you loop through each element, this same effect is called multiple times.

Adding a custom attribute in ASP.NET. accessing it in JQuery

I have a table that is created in ASP.NET C# code behind. The table has several levels of groupings, and when I create the rows for the outer most grouping, I add an custom attribute as follows:
foreach (Table2Row row in Table2Data)
{
// skipping a bunch of irrelevent stuff
...
tr_group.Attributes.Add("RowsToToggle", String.Format(".InnerRowGroupId_{0}", row.GroupHeaderId));
...
}
The attribute is the CSS class name of the inner level rows that I would like to toggle. When the user clicks on the outer level row, I would like to call JQuery Toggle function for all inner level rows that match the custom attribute.
To achieve that effect, I have attached an onclick event to the header rows with the following script in the aspx file:
var tableId = '<%= Table2MainTable.ClientID %>';
$(document).ready(function () {
var table = document.getElementById(tableId);
var groupRows = table.getElementsByClassName("Table2GroupHeaderRow");
for (i = 0; i < groupRows.length; i++) {
table.groupRows[i].onclick = function () { ToggleOnRowClick(table.rows[i]); }
}
});
function ToggleOnRowClick(row) {
var r = $('#' + row.id);
var innerRows = r.attr('RowsToToggle');
$(innerRows ).toggle();
}
So, clicking anywhere on the header row should call the function ToggleOnRowClick, which should then toggle the set of rows below it via the custom attribute RowsToToggle.
When I set a (FireBug) break point in the ToggleOnRow function, the variable r appears to be pointing to the correct object. However, innerRows is not getting set but instead remains null. So am I setting the custom attribute incorrectly in ASP.NET or reading in incorrectly in JQuery?
You did not post the code to generate inner level rows, I am assuming you sat proper classes to them.
There are few issues with the jquery you posted. This line wouldn't work:
table.groupRows[i].onclick = function () { ToggleOnRowClick(table.rows[i]); }
You don't have any groupRows property defined for table object.
We don't care about table row anymore, we care about groupRows[i] and want to pass it to ToggleOnRowClick function.
This line in next function is also wrong:var r = $('#' + row.id);
Solution: Change your script to this:
var tableId = '<%= Table2MainTable.ClientID %>';
$(document).ready(function () {
var table = document.getElementById(tableId);
var groupRows = table.getElementsByClassName("Table2GroupHeaderRow");
for (i = 0; i < groupRows.length; i++) {
groupRows[i].onclick = function () { ToggleOnRowClick(this); }
}
});
function ToggleOnRowClick(row) {
//var r = $('#' + row.id);
var innerRows = $(row).attr('RowsToToggle');
$("." + innerRows).toggle();
}
I have tested the code with dummy data. So if you have any issue, PM me.
This line is your culprit:
table.groupRows[i].onclick = function () { ToggleOnRowClick(table.rows[i])
By the time the event handler runs, table.rows might still exist, but i will be set to groupRows.length+1, which is out of bounds for the array. The handler will get called with an argument of undefined.
Remember, Javascript is an interpreted language! The expression "table.rows[i]" will get interpeted when the handler runs. It will use the last value of i (which will still be set to the value that caused your for loop to end, groupRows.length+1).
Just use
table.groupRows[i].onclick = function () { ToggleOnRowClick(this) }
So, First you shouldn't use custom attributes... they are a sin!
Please use data attributes instead, so that is what I'm going to use in the code, should be an easy fix regardless.
If this doesn't work then I'd be very very interested in seeing a dumbed down HTML snippet of the actual output.
$(document).ready(function () {
$('#MYTABLE').on('click', '.Table2GroupHeader', function() {
var attr_if_you_insist_on_sinning = $(this).attr("RowsToToggle");
var data_if_you_like_not_sinning = $(this).data("RowsToToggle");
//if the row is like <tr data-RowsToToggle=".BLAH" or th etc
//asumming you set the attribute to .BLAH then:
var rows_to_toggle = $(data_if_you_like_not_sinning);
rows_to_toggle.toggle();
//assuming you set it to BLAH then:
var rows_to_toggle = $("."+ data_if_you_like_not_sinning);
rows_to_toggle.toggle();
});
});
$(document).ready(function () {
$('#<%= Table2MainTable.ClientID %> .Table2GroupHeader').each(function(){
$(this).click(function(){
$(this).toggle();
});
});
});

Categories