"Primitive value will be lost" warning in WebStorm [duplicate] - javascript

I created a function:
function CheckHidden(el){ return $(el).css('display')!='none' }
My IDE warns me that:
Primitive value returned from constructor will be lost when called with 'new'
Actually when I call it like this:
var all = $("#catalog-body > div").filter(function(){return CheckHidden(this)})
it doesn't work and doesn't reduce set of elements to unhidden ones.
Please explain to me the issue. I have a giant lack of knowledge.

I ran into this warning myself and if you want to know the cause, it is because your IDE expect function names to start with a lowercase letter. Since your function is called CheckHidden with a capital C, it thinks it's a class declaration.
However, you should still use jQuery's :visible selector to fix your specific issue.

If you create an object using the keyword new (as mentioned in the warning), JS returns an new instance of the object rather than the return value from the constructor.
A function like
function CheckHidden() {
return false;
}
would return two different values, depending on how it is executed.
// "a" is boolean value
var a = CheckHidden();
// "a" is an object of type "CheckHidden"
var a = new CheckHidden();

jQuery actually has something like this built in. You can use the :visible selector. You can just do:
var all=$("#catalog-body > div").filter(':visible')
to get the visible elements.

If you want to pull all elements which are visible, you can use jQuery's :visible selector:
var all = $("#catalog-body > div:visible")
Conversely, if you want to pull all elements which are hidden, you can combine this with jQuery's :not selector:
$("#catalog-body > div:not(:visible)")

Related

What does $($(this)) mean?

I saw some code around the web that uses the following statement
if ($($(this)).hasClass("footer_default")) {
$('#abc')
.appendTo($(this))
.toolbar({position: "fixed"});
}
What is the use of $($(this)) and why is that necessary here?
Yes, $($(this)) is the same as $(this), the jQuery() or $() function is wonderfully idempotent. There is no reason for that particular construction (double wrapping of this), however, something I use as a shortcut for grabbing the first element only from a group, which involves similar double wrapping, is
$($('selector')[0])
Which amounts to, grab every element that matches selector, (which returns a jQuery object), then use [0] to grab the first one on the list (which returns a DOM object), then wrap it in $() again to turn it back into a jQuery object, which this time only contains a single element instead of a collection. It is roughly equivalent to
document.querySelectorAll('selector')[0];, which is pretty much
document.querySelector('selector');
You can wrap $ as many times as you want, it won't change anything.
If foo is a DOM element, $(foo) will return the corresponding jQuery object.
If foo is a jQuery object, $(foo) will return the same object.
That's why $($(this)) will return exactly the same as $(this).
There is no specific need for double-wrapping and $($(this)) is exactly the same as $(this).
That said, I once found this double-wrapping in one file in my project, committed by another developer. Tracking the changes through revision, turned out that it started as $($(this).find('selector').first()) - that is, the result of some selector was wrapped to create a new object. Then for whatever reasons, the selector was removed and only the double-wrapping of this remained. Needless to say, on the next commit it was changed to $(this).
As explained before me, $($(this)) and $(this) are absolutely identical. jQuery returns the same jQuery object if you try to wrap it more than once.
Additionally, for performance considerations it is a good practice to reuse jQuery objects - it is quite expensive to create jQuery objects, especially the ones with complex selectors. Example:
var $this = $(this);
if ($this.hasClass("footer_default")) {
$('#abc')
.appendTo($this)
.toolbar({position: "fixed"});
}
Just google for 'jQuery best practices' - it will take a 30 min for you to learn these basics and you will use jQuery way more effectively.
There is no meainig of doing that.
The following code return the same:
console.log($($(this)).hasClass("footer_default"))
console.log($(this).hasClass("footer_default"))
a boolean value depenging on if the selected element has or not the class footer_default:
.hasClass( className )Returns: Boolean
Demo: http://jsfiddle.net/IrvinDominin/aSzFn/
$(this) and $($(this)) both return jquery object.
There is no difference between these two.

setting default root element in jquery

jQuery currently uses window as its default element so any call like $('div') will look for div tags inside window.
Is there any way to change defaults on jQuery like:
$.defaultRoot = $('.anyOtherRootElement');
$('div').text("Hello");
this will select any div inside the elements containing .anyOtherRootElement class.
Thanks in advance
Upate
just an update refining the question a bit more here:
I would like to perform the actions above based on external queries coming from external script which won't know what defaultRoot is so they can still be calling what is supposed to be the current base, so in this instance, I'm afraid adding the a second parameter wouldn't be an option, unfortunately.
And at the same time creating a function which returns defaultRoot.find(el) would prevent me of using first-level methods such $.trim, $.each, etc… so unfortunately that would not be possible as well.
Ideally (for performance reasons) you'd want to use find()
$.defaultRoot.find("div");
Otherwise you can use the 2 argument form that sets a context
$("div", $.defaultRoot);
In general you don't want to do these types of things implicitly since someone else could easily end up thoroughly confused when having to work with your code later. If you want to do it consistently and make it shorter you should create your own function to do so like:
var $s = function(selector) {
return $.defaultRoot.find(selector);
}
and then you'd just be able to use
$s("div")
or you could also do a scoped higher order function with something like
var withScope = function(scope$) {
return function(selector) {
return scope$.find(selector);
}
}
var $s = withScope($.defaultRoot);
$s("div")
If for some reason you really want to screw around with the default state for client code (begging for chaos IMO), you should look at the functional practice: currying.
$('SELECTOR', 'CONTEXT')
You can use context. As in your case $('div', '.anyOtherRootElement')
For more details, visit http://api.jquery.com/jQuery/
Given that you can pass the context as a second argument, you can easily overwrite the $() operator in Javascript with a version which internally calls JQuery using jQuery.noConflict(); and always passes your new root as the second argument.
I don't think jQuery provide such method or variable. But you can pass second parameter in jQuery method to set context.
$.defaultRoot = $('.anyOtherRootElement');
$('div', $.defaultRoot ).text("Hello"); // all div inside $('.anyOtherRootElement')
$('div' ).text("Hello"); //all div inside body tag

Getting the "match" object in a Custom Filter Selector in jQuery 1.8

For reference, here's an article on Creating a Custom Filter Selector with jQuery.
Introduction:
For those not familiar with jQuery's Custom Filter Selectors, here's a quick primer on what they are:
If you need a reusable filter, you can extend jQuery’s selector expressions by adding your own functions to the jQuery.expr[':'] object.
The function will be run on each element in the current collection and should return true or false (much like filter). Three bits of information are passed to this function:
The element in question
The index of this element among the entire collection
A match array returned from a regular expression match that contains important information for the more complex expressions.
Once you've extended jQuery.expr[':'], you can use it as a filter in your jQuery selector, much like you would use any of the built-in ones (:first, :last, :eq() etc.)
Here's an example where we'll filter for elements that have more than one class assigned to them:
jQuery.expr[':'].hasMultipleClasses = function(elem, index, match) {
return elem.className.split(' ').length > 1;
};
$('div:hasMultipleClasses');
Here's the fiddle: http://jsfiddle.net/acTeJ/
In the example above, we have not used the match array being passed in to our function. Let's try a more complex example. Here we'll create a filter to match elements that have a higher tabindex than the number specified:
jQuery.expr[':'].tabindexAbove = function(elem, index, match) {
return +elem.getAttribute('tabindex') > match[3];
};
$('input:tabindexAbove(4)');
Here's the fiddle: http://jsfiddle.net/YCsCm/
The reason this works is because the match array is the actual array returned from the regex that was used to parse the selector. So in our example, match would be the following array:
[":tabIndexAbove(4)", "tabIndexAbove", "", "4"]
As you can see, we can get to the value inside the parentheses by using match[3].
The Question:
In jQuery 1.8, the match array is no longer being passed in to the filter function. Since we have no access to the info being passed in, the tabindexAbove filter does not work anymore (the only difference between this fiddle and the one above, is that this uses a later version of jQuery).
So, here are several points I'd like clarified:
Is this expected behavior? Is it documented anywhere?
Does this have anything to do with the fact that Sizzle has been updated (even though it clearly states that "the old API for Sizzle was not changed in this rewrite". Maybe this is what they mean by "the removal of the now unnecessary Sizzle.filter")?
Now that we have no access to the match array, is there any other way to get to the info being passed in to the filter (in our case, 4)?
I never found any documentation in the jQuery Docs about the custom filter selectors, so I don't know where to start looking for information about this.
jQuery has added a utility for creating custom pseudos in Sizzle. It's a little more verbose, but it's much more readable than using match[3]. It also has the advantage of being more performant as you can avoid repeating tedious calculations every time an element is tested. The answer that has already been accepted is a good answer, but let me add a note to say that you can use $.expr.createPseudo instead of setting the sizzleFilter property yourself, which will save a little space.
jQuery.expr[':'].tabIndexAbove = $.expr.createPseudo(function( tabindex ) {
return function(elem) {
return +elem.getAttribute('tabindex') > tabindex;
}
});
$('input:tabIndexAbove(4)').css('background', 'teal');
jsfiddle: http://jsfiddle.net/timmywil/YCsCm/7/
This is all documented on Sizzle's github:
https://github.com/jquery/sizzle/wiki/Sizzle-Documentation
By looking at the jQuery 1.8 beta2 source and the "Extensibility" section of The New Sizzle, you have to set fn.sizzleFilter to true in order to get the pseudo argument and the context. If not, you'll just get all the elements in the arguments.
Here is the code that does the same thing as your example. Use the selector parameter passed in the function to get the pseudo argument.
Here is the working example on jsfiddle.
As mentioned in the blog post above, you can even pre-compile and cache the your selector.
var sizzle = jQuery.find;
var tabIndexAbove = function( selector, context, isXml ) {
return function( elem ) {
return elem.getAttribute("tabindex") > selector;
};
};
/*
fn.sizzleFilter is set to true to indicate that tabIndexAbove
is a function that will return a function for use by the compiler
and should be passed the pseudo argument, the context, and
whether or not the current context is xml. If this property is
not set, adding pseudos works similar to past versions of Sizzle
*/
tabIndexAbove.sizzleFilter = true;
sizzle.selectors.pseudos.tabIndexAbove = tabIndexAbove;
$('input:tabIndexAbove(4)').css('background', 'teal');
Just a note, if you're looking at the source, jQuery slightly changed the structure that the public-facing interface points to.
In jQuery 1.7.2:
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.filters;
In jQuery 1.8b2:
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.pseudos;

Determine if a string is a valid jQuery selector?

Does jQuery have a method to determine if an argument passed to function is a selector?
I am making a template for some jQuery plugins and I need to be able to check if the argument passed in is a jQuery selector. I want to allow for other data types and perform different methods based on what data type is passed. Detecting data types is easy, but selectors are just a string and can be constructed is many different ways.
My goal is to create plugins that are forgiving with what you pass in for the arguments and makes educated decisions about what to do with it. Take the jQuery UI plugins for example, in some plugins, lets say we pass a callback function in the argument place holder that is for a number for a speed, it still takes the callback and runs it and uses the default for speed. That's the kind of functionality I'm going for and selectors are a pretty unique case.
Has jQuery written a Regex for this? I couldn't find one in the code.
If not, I guess I'll just have to write a huge Regex for this?
To go straight to the point:
No, jQuery has no method to check if a selector is valid.
jQuery has lots of Regex' for this, that's why you cannot find one in the code.
You do not have to write a huge Regex for this, the answer is more simple as shown below.
I understand your problem because I experienced it, there are cases in which you're not in control of the selector to give to the jQuery function.
The problem not outlined enough is that if a selector is not valid jQuery throws an error (it is important because here is the answer).
Example using jQuery v1.9.1:
$('##somewhere');
It logs into the console the following line:
throw new Error( "Syntax error, unrecognized expression: " + msg );
which source is at row 4421 of the jQuery.js file (non-minified and uncompressed version).
So, instead of looking for an inner method of jQuery (which could surely simplify things but is not available), you can just listen the error thrown to establish if the selector is valid:
function isValidSelector(selector) {
if (typeof(selector) !== 'string') {
return false;
}
try {
var $element = $(selector);
} catch(error) {
return false;
}
return true;
}
You can also make it a jQuery plugin:
jQuery.extend({
isValidSelector: function(selector) {
if (typeof(selector) !== 'string') {
return false;
}
try {
var $element = $(selector);
} catch(error) {
return false;
}
return true;
}
});
to be used this way:
alert($.isValidSelector('#what?!?'));
Best regards.
EDIT:
added type validation: the selector must be a string.
Anyhow it is a partial solution, it does not return false for selectors defined as string objects var selector = new String('##wrong-selector#!');, which are not a primitive type.
Lots of strings can technically be a selector like $('blah') could select custom elements! There isn't any good way of knowing the intent of what to do with the argument passed to your function, so it's best to have a well defined structure like Gaby has commented.
Selector:
yourFunction({ selector: 'div' });
Or
yourFunction({ value: 'testing' });
Will take a different route in your code.
Without this technique the best you can do is just attempt for jQuery to find elements based on the selector, check with .length, if elements are found then assume the caller intended a jQuery selector. Another option could be just to document that a jQuery object must be passed i.e.:
yourFunction({ value: jQuery('div') });
Then for a different route you can do
if (value instanceof of jQuery) { .... }
There can not be a regex for this, since the selectors are extensible and anyone could add any number of personal selectors (with custom defined symbols etc) ...
Perhaps you should try passing your arguments as a single object with named parameters.
{ selector:'...',
otherargument:'somevalue',
afunction: function(){...}
}
The jQuery code for determining the selector is valid is about 108 lines long, so don't expect to determine if it's a valid selector or not in one RegEx statement.
Your best bet is probably to look at what jQuery determines to be a valid selector, and make a function that essentially checks the same way, but returns whether it's valid or not.
https://github.com/jquery/jquery/blob/master/src/core.js#L80-188
This does not answer your question, but i think it can be helpful. It checks not if an argument is a jQuery selector, however it tests whether the selector exists in the document.
$.fn.inDom = function() { return $(document).find(this).length; };
BTW: I dont use $(selector).length directly, since it will return 1 if the passed argument is an HTMLNode.
For better interpretation purposes:
$('foo').length // 0
$('.foo').length // 0
$('#foo').length // 0
$('<foo>').length // 1
$(document).find('foo').length // 0
$(document).find('.foo').length // 0
$(document).find('#foo').length // 0
$(document).find('<foo>').length // 0

Jquery Replace with return value of Javascript function

OK I am just starting out with jQuery.
I have a page with a table of date-values. Each is wrapped in a tag which I can find with
$('mytag').
<mytag>2009-10-31</mytag>
How, using Jquery, would I
take each of the source values and
pass it to a Javascript function
then replace that source value within the table with the result of the function calculation.
So <mytag>2009-10-31</mytag>would be replaced with <mytag>Very Late</mytag>
I have the Javascript function written. My question is the jQuery syntax to pass the individual value.
Firstly, you will need an element selector, e.g.
$('table')
Will select all <table> elements in your html. So,
$('mytag')
will give you your elements. You will get a jQuery object (not a DOM object) returned. See http://docs.jquery.com/Selectors
Then you want to call a function for each of your elements. For this we call the .each function, and pass the function to call for each element:
$('mytag').each(function(){
//function code goes here
});
(See http://docs.jquery.com/Utilities/jQuery.each)
The function in this case is called an Anonymous function
Then you want to reference the current object in the iteration, so we use the DOM this item and wrap it into a jquery object. To get the value, we use the .text() function (http://docs.jquery.com/Attributes/text)
$('mytag').each(function(){
$(this).text()
});
Note: if it were an input element then you would have used .val()
Passing it to a function is easy:
...
MyFunction($(this).text());
...
The text() function has an overloaded implementation which allows you to set the text if you pass a value:
$(this).text(someval);
So, we can factor this into our code
...
$(this).text(MyFunction($(this).text()));
...
Making our final code block:
$('mytag').each(function(){
$(this).text(MyFunction($(this).text()));
});
$('mytag').each(function (index,tag) {
$(tag).text( myFunc($(tag).text()) );
});
$("mytag").each(function() {
$(this).html("Very Late");
});
$('mytag').each(function() {
$(this).text(someFunction($(this).text()));
});
But, from the sound of your problem, you might be better served by the jQuery-timeago plugin. For your particular case, you'd possibly want to allow dates in the future:
jQuery.timeago.settings.allowFuture = true;
...and you'd want to create your own language override. See the language override examples. You could define several "late" and "very late" values. You can also pass a function to each one to change the value depending on how many days ago a timestamp was.

Categories

Resources