I have a few divs with the .class class whose scroll position is defined by another child of its parent, so I need to assign a scrollTop() with $(this), something like
$(".class").scrollTop($(this).parent().find('.child').scrollTop());
But that code doesn't work...
$(".class").scrollTop(
function(){
$(this).parent().find('.child').scrollTop()
}
);
Doesn't work either. Any clue?
This is assuming that I am reading your question right. You have mulitple "class" elements that have their own "child" elements. You would need to use each to set every element separately.
$(".class").each(
function(){
var elem = $(this);
var childsScrollPosition = elem.parent().find('.child').scrollTop();
elem.scrollTop(childsScrollPosition);
}
);
ScrollTop wants an integer for the position so passing the DOM node wont help.
Try caching your selector and pass it with the position method:
var scrollTo = $(this).parent().find('.child');
$(".class").scrollTop( scrollTo.position().top );
Or you use offset depending on your use case:
var scrollTo = $(this).parent().find('.child');
$(".class").scrollTop( scrollTo.offset().top );
I am doing this blind here but this should work too:
var scrollTo = $(this).parent().find('.child');
$(".class").scrollTop(
function() {
return scrollTo.offset().top;
}
);
Does this help?
Related
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.
I have created "myCanvas" div element dynamically and try to set styles to the div tag it throw the undefined exception. Please check my code and suggest me
// move the canvas, so it's contained by the same parent as the image
var imgParent = img.parentNode;
$('<div id="myCanvas">');
var can = $('myCanvas');
can.appendTo(imgParent);
// position it over the image
can.style.left = x + 'px'; //If set styles to can element, it's styles is undefined
What i did wrong here.. ? please anyone suggest me a right things..
Thanks,
Bharathi
Make is simple:
$('<div id="myCanvas">').appendTo(img.parentNode).css('left', x);
You don't need to select the myCanvas element because it hasn't been added to the DOM just yet (your selector wasn't right either). You can use this instead:
var imgParent = img.parentNode;
// By default when creating an element in jQuery, it returns an instance of the jQuery object created
var can = $('<div id="myCanvas">');
can.appendTo(imgParent);
can.style.left = x + 'px';
Replace
var can = $('myCanvas');
with
var can = $('#myCanvas');
[edit user="dholakiyaankit"]
QA asking for id not class
Antegias response should read
Replace ... with :
var can = $('#myCanvas');
as you have given it an id not a class, you cant select it in this way till its added to DOM, but you have a reference to it anyway in the variable can
I figured I would get fancy and use vanilla JavaScript during a jQuery event. The idea is that on click of a heading, I want to slide up a div (which works) and replace the tag clicked on to a larger heading.
From what I've read around, this can be caused by the parentNode referencing an element that's not the actual parent, but after checking it appears to be selecting the element that's directly above it.
So... here's the code!
HTML (in Jade)
.policy-container
h6.policy-heading Policies
.policy-list
.content-we-are-hiding
.not-actually-important
jQuery
$('.policy-heading').click(function() {
var self = this;
if (this.classList.contains('closed')) {
$(this).next().slideDown(300);
this.parentNode.replaceChild(self, '<h6 class="policy-heading">Policies</h6>');
} else {
$(this).next().slideUp(300);
this.parentNode.replaceChild(self, '<h2 class="policy-heading closed">Policies</h2>');
}
});
Everything seems pretty standard. Luckily I can just take care of this with jQuery, however I'd rather be using vanilla JS here. Any ideas why this isn't working?
As has been pointed out, replaceChild takes two nodes.
The following will work with native JS wrapped inside jQuery, as you've specified:
$('.policy-heading').click(function () {
var self = this,
h2 = document.createElement('h2'),
h6 = document.createElement('h6');
h2.class = "policy-heading closed";
h2.innerHTML = "Policies";
h6.class = "policy-heading";
h6.innerHTML = "Policies";
if (this.classList.contains('closed')) {
$(this).next().slideDown(300);
this.parentNode.replaceChild(h6, self);
} else {
$(this).next().slideUp(300);
this.parentNode.replaceChild(h2, self);
}
});
replaceChild takes two nodes, you are giving it a node and a string.
It looks like you'd be much better off just sticking with jQuery and using toggle functions for the sliding and class change.
try this :
.click(function(this)
you also need some debugging to understand what is going on I would advice you to use :
console.log(this)
use this :
el = document.createElement('h6');
el.class = "policy-heading";
el.innerHTML = "Policies";
this.parentNode.replaceChild(self, el);
As everyone pointed out, .replaceChild accepts two DOM elements, rather than the string like I was using. I also had its arguments backwards, the first is for the new element, the second is the replaced element.
Example code that works
$('.policy-container').on('click', '.policy-heading', function() {
var self = this,
newElement;
if (this.classList.contains('closed')) {
newElement = document.createElement( 'h6' );
newElement.classList.add('policy-heading');
newElement.innerHTML = 'Policies';
} else {
newElement = document.createElement( 'h2' );
newElement.classList.add('policy-heading');
newElement.classList.add('closed');
newElement.innerHTML = 'Policies';
}
$(this).next().slideDown(300, function() {
self.parentNode.replaceChild( newElement, self );
});
});
So I need to add tooltips for some input fields and textareas. Currently, I have it setup like this:
$(document).ready(function(){
$('input').focus(function(){
var p = $(this);
var position = p.position();
var input_name = $(this).attr('id');
var name = '#'+input_name+'_help';
$('#apply_tooltip').css("left", position.left - 310 );
$('#apply_tooltip').css("top", position.top -15 );
$(name).show();
$('#apply_tooltip').show();
});
$('input').blur(function(){
$('.tooltip_inner').hide();
$('#apply_tooltip').hide();
});
$('textarea').focus(function(){
var p = $(this);
var position = p.position();
var input_name = $(this).attr('id');
var name = '#'+input_name+'_help';
$('#apply_tooltip').css("left", position.left - 310 );
$('#apply_tooltip').css("top", position.top -15 );
$(name).show();
$('#apply_tooltip').show();
});
$('textarea').blur(function(){
$('.tooltip_inner').hide();
$('#apply_tooltip').hide();
});
});
This works, but obviously there is probably a more efficient solution than simply duplicating the functions... Is there anyway to target both input fields and textareas with the same functions?
Instead of this:
$('input').focus(function(){
you can use this to get both types of objects with the same jQuery object and thus the same function:
$('input, textarea').focus(function(){
Though this isn't needed here, you ought to know that you can also put common code in a function and call that one function from multiple places rather than copying code into multiple places. Basically, you should pretty much never copy the same block of code into multiple places.
Another option is to refactor. In this specific case, jfriend00's answer is suitable, but if you needed to pass arbitrary arguments, e.g., the top or left positions, you can always pull out a method.
function tt(p) {
var position = p.position();
var input_name = p.attr('id');
var name = '#'+input_name+'_help';
$('#apply_tooltip').css("left", position.left - 310 );
$('#apply_tooltip').css("top", position.top -15 );
$(name).show();
$('#apply_tooltip').show();
}
$('input').focus(function() {
tt($(this));
});
$('textarea').focus(function() {
tt($(this));
});
My approach would be to do the alignment with CSS (with position: absolute if necessary) and set the tool tip to:
display: none;
Then in jquery you would only have to navigate the DOM and show/hide (or fadeIn fadeOut if you want to get sexy with it).
$('input').focus(function(){
$(this).siblings('.tip').show();
}).blur(function(){
$(this).siblings('.tip').hide();
});
I got some help earlier regarding selectors, but I'm stuck with the following.
Lets say you have a plugin like this
$('#box').customplugin();
how can I get the #box as a string in the plugin?
Not sure if that's the correct way of doing it, and any other solution would be great as well.
Considering #box is a select dropdown,
The problem I'm having is if I do the regular javascript
$('#box').val(x);
The correct option value gets selected,
but if i try the same inside a plugin
.....
this.each(function() {
var $this = $(this);
$this.val(x);
the last code doesn't really do anything.
I notice I'm having trouble targeting #box inside the plugin because it's a object and not a string...
Any help would be appreciated.
Thanks!
Edit:: Putting in the code I'm working in for better understanding
(function($){
$.fn.customSelect = function(options) {
var defaults = {
myClass : 'mySelect'
};
var settings = $.extend({}, defaults, options);
this.each(function() {
// Var
var $this = $(this);
var thisOpts = $('option',$this);
var thisSelected = $this[0].selectedIndex;
var options_clone = '';
$this.hide();
options_clone += '<li rel=""><span>'+thisOpts[thisSelected].text+'</span><ul>'
for (var index in thisOpts) {
//Check to see if option has any text, and that the value is not undefined
if(thisOpts[index].text && thisOpts[index].value != undefined) {
options_clone += '<li rel="' + thisOpts[index].value + '"><span>' + thisOpts[index].text + '</span></li>'
}
}
options_clone += '</ul></li>';
var mySelect = $('<ul class="' + settings.myClass + '">').html(options_clone); //Insert Clone Options into Container UL
$this.after(mySelect); //Insert Clone after Original
var selectWidth = $this.next('ul').find('ul').outerWidth(); //Get width of dropdown before hiding
$this.next('ul').find('ul').hide(); //Hide dropdown portion
$this.next('ul').css('width',selectWidth);
//on click, show dropdown
$this.next('ul').find('span').first().click(function(){
$this.next('ul').find('ul').toggle();
});
//on click, change top value, select hidden form, close dropdown
$this.next('ul').find('ul span').click(function(){
$(this).closest('ul').children().removeClass('selected');
$(this).parent().addClass("selected");
selection = $(this).parent().attr('rel');
selectedText = $(this).text();
$(this).closest('ul').prev().html(selectedText);
$this.val(selection); //This is what i can't get to work
$(this).closest('ul').hide();
});
});
// returns the jQuery object to allow for chainability.
return this;
}
Just a heads-up: .selector() is deprecated in jQuery 1.7 and removed in jQuery 1.9: api.jquery.com/selector.
– Simon Steinberger
Use the .selector property on a jQuery collection.
Note: This API has been removed in jQuery 3.0. The property was never a reliable indicator of the selector that could be used to obtain the set of elements currently contained in the jQuery set where it was a property, since subsequent traversal methods may have changed the set. Plugins that need to use a selector string within their plugin can require it as a parameter of the method. For example, a "foo" plugin could be written as $.fn.foo = function( selector, options ) { /* plugin code goes here */ };, and the person using the plugin would write $( "div.bar" ).foo( "div.bar", {dog: "bark"} ); with the "div.bar" selector repeated as the first argument of .foo().
var x = $( "#box" );
alert( x.selector ); // #box
In your plugin:
$.fn.somePlugin = function() {
alert( this.selector ); // alerts current selector (#box )
var $this = $( this );
// will be undefined since it's a new jQuery collection
// that has not been queried from the DOM.
// In other words, the new jQuery object does not copy .selector
alert( $this.selector );
}
However this following probably solves your real question?
$.fn.customPlugin = function() {
// .val() already performs an .each internally, most jQuery methods do.
// replace x with real value.
this.val(x);
}
$("#box").customPlugin();
This page talks about getting the selector:
http://api.jquery.com/selector/
That's how I get selector strings inside my plugins in 2017:
(function($, window, document, undefined) {
$.fn._init = $.fn.init
$.fn.init = function( selector, context, root ) {
return (typeof selector === 'string') ? new $.fn._init(selector, context, root).data('selector', selector) : new $.fn._init( selector, context, root );
};
$.fn.getSelector = function() {
return $(this).data('selector');
};
$.fn.coolPlugin = function() {
var selector = $(this).getSelector();
if(selector) console.log(selector); // outputs p #boldText
}
})(jQuery, window, document);
// calling plugin
$(document).ready(function() {
$("p #boldText").coolPlugin();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>some <b id="boldText">bold text</b></p>
The idea is to conditionally wrap jQuery's init() function based on whether a selector string is provided or not. If it is provided, use jQuery's data() method to associate the selector string with the original init() which is called in the end. Small getSelector() plugin just takes previously stored value. It can be called later inside your plugin. It should work well with all jQuery versions.
Because of the deprecation and removal of jQuery's .selector, I have experimented with javascript's DOM Nodes and came up with a 2017 and beyond solution until a better way comes along...
//** Get selector **//
// Set empty variables to work with
var attributes = {}, // Empty object
$selector = ""; // Empty selector
// If exists...
if(this.length) {
// Get each node attribute of the selector (class or id)
$.each(this[0].attributes, function(index, attr) {
// Set the attributes in the empty object
// In the form of name:value
attributes[attr.name] = attr.value;
});
}
// If both class and id exists in object
if (attributes.class && attributes.id){
// Set the selector to the id value to avoid issues with multiple classes
$selector = "#" + attributes.id
}
// If class exists in object
else if (attributes.class){
// Set the selector to the class value
$selector = "." + attributes.class
}
// If id exists in object
else if (attributes.id){
// Set the selector to the id value
$selector = "#" + attributes.id
}
// Output
// console.log($selector);
// e.g: .example #example
So now we can use this for any purpose. You can use it as a jQuery selector... eg. $($selector)
EDIT: My original answer would only get the attribute that appears first on the element. So if we wanted to get the id that was placed after the class on the element, it wouldn't work.
My new solution uses an object to store the attribute information, therefore we can check if both or just one exists and set the required selector accordingly. With thanks to ManRo's solution for the inspiration.