My function returns empty. why? - javascript

I know that this is a basic question but I am stuck with it somewhere in my code. I got that code from somewhere but now I am modifying it according to my need.
What does jQuery('#selector') do? In my code it always return empty.
Here is my code
query: function (selector, context) {
var ret = {}, that = this, jqEls = "", i = 0;
if(context && context.find) {
jqEls = context.find(selector);
} else {
jqEls = jQuery(selector);
}
ret = jqEls.get();
ret.length = jqEls.length;
ret.query = function (sel) {
return that.query(sel, jqEls);
}
return ret;
}
when I call this query function then I pass selector as parameter. When I do console.log(selector) it does have all the selectors which I need in this function. But the problem is on this line jqEls = jQuery(selector);. when I do console.log(jqEls) after this it returns empty thus the whole function returns empty.
Can I use something different then this to make it work?

jquery('#selector') is the equivalent of document.getElementById('selector'). If there is no DOM node with an id of selector, you get an empty result.
e.g.
<div id="selector">...</div>
would return the dom node corresponding to this div. Do you have jquery loaded?

jQuery(selector) is looking for a DOM element that meets the selector criteria.
$('#example') == jQuery('#example')
Both will look for something with id "example"

$(selector).get() will return undefined if no element is found. This is why your function returns undefined. To fix this, you could use a default value if there is no element found:
ret = jqEls.length ? jqEls.get() : {};
This way your function will always return an object that has your length and query properties, but it will not have an element if jQuery did not find one.

After reading your code I have a question : do you put the # in your variable selector ?
A solution to solve this by replacing the bad line by jqEls = jQuery("#" + selector);
If the problem isn't due to that can you say the type of selector ? string ? object ? jQueryObject ?

Related

JavaScript: Pass conditional condition as value

I have a function that finds elements using jQuery. I then take that element, get a value from it and assign it to a variable. However, sometimes an element will not exist on the document and the function will return undefined. This is expected and if the element returned is undefined then the variable that gets assigned should also be undefined. Since I am using this function to assign variables many times I wanted to make it neat and on one line. I thought using conditionals might be a solution, however, doing this leads to really messy long lines and needing to call the function twice:
let html = $(response.body);
let language = getRowElementFromText('Language', html) ? getRowElementFromText('Language', html).find('a').text() : undefined;
let pages = getRowElementFromText('Page', html) ? parseInt(getRowElementFromText('Page', html).text()) : undefined;
Is it possible to resolve those issues and somehow pass the condition of the conditional to be used as the value? For example, in this pesudo code this would be the value of the conditional:
let html = $(response.body);
let language = getRowElementFromText('Language', html) ? this.find('a').text() : undefined;
let pages = getRowElementFromText('Page', html) ? parseInt(this.text()) : undefined;
If this not possible is there another more readable way I can accomplish this on one line?
It is/will be with the optional chaining operator that's new in ES2020 (available via transpilation today). the code would look like this (it only helps so much with the parseInt cas):
let language = getRowElementFromText('Language', html)?.find('a').text();
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^
let pageText = getRowElementFromText('Page', html)?.text();
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^
let pages = pageText ? parseInt(pageText) : undefined;
language would be undefined if the element wasn't found.
If you can't use it (because your target environments don't have it yet and you're not transpiling), you could pass in a function that getRowElementFromText will call if the element is found:
let html = $(response.body);
let language = getRowElementFromText('Language', html, el => el.find('a').text());
let pages = getRowElementFromText('Page', html, el => parseInt(el.text()));
getRowElementFromText would look like this:
function getRowElementFromText(text, html, callback) {
const result = /*...existing logic...*/;
return result === undefined ? undefined : callback(result);
}
Or perhaps like this (callback is optional):
function getRowElementFromText(text, html, callback) {
const result = /*...existing logic...*/;
return !callback || result === undefined ? result : callback(result);
}
Note: In the above I'm assuming getRowElementFromText does actually return undefined in some cases ("not found"), and returns a jQuery object in other cases (found). I flag this up because if it always returns a jQuery object (which may be empty), jQuery objects are never falsy (not even empty ones).
Add the following function to jQuery prototype. It receives a fallback string as an argument and when element is not found, returns fallback string:
$.prototype.getText = function(fallback = undefined) {
return this.length > 0 ? this.text() : fallback
}
console.log($("#foo").getText())
console.log($("#bar").getText("If the element does not exists, returns given fallback string"))
console.log(`Fallback string default value is: ${$("#baz").getText()}`)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<label id="foo">If the element exists, return its inner text</label>
Usage:
$(selector).getText(fallbackString);

How to compare if an HTML element exists in the node array?

selectedContentWrap: HTML nodes.
htmlVarTag: is an string.
How do I check if the HTML element exists in the nodes?
The htmlVarTag is a string and don't understand how to convert it so it check again if there is a tag like that so that if there is I can remove it?
here is output of my nodes that is stored in selectedContentWrap
var checkingElement = $scope.checkIfHTMLinside(selectedContentWrap,htmlVarTag );
$scope.checkIfHTMLinside = function(selectedContentWrap,htmlVarTag){
var node = htmlVarTag.parentNode;
while (node != null) {
if (node == selectedContentWrap) {
return true;
}
node = node.parentNode;
}
return false;
}
Well if you could paste the content of selectedContentWrap I would be able to test this code, but I think this would work
// Code goes here
var checkIfHTMLinside = function(selectedContentWrap,htmlVarTag){
for (item of selectedContentWrap) {
if (item.nodeName.toLowerCase() == htmlVarTag.toLowerCase()){
return true;
}
}
return false;
}
Simplest is use angular.element which is a subset of jQuery compatible methods
$scope.checkIfHTMLinside = function(selectedContentWrap,htmlVarTag){
// use filter() on array and return filtered array length as boolean
return selectedContentWrap.filter(function(str){
// return length of tag collection found as boolean
return angular.element('<div>').append(str).find(htmlVarTag).length
}).length;
});
Still not 100% clear if objective is only to look for a specific tag or any tags (ie differentiate from text only)
Or as casually mentioned to actually remove the tag
If you want to remove the tag it's not clear if you simply want to unwrap it or remove it's content also ... both easily achieved using angular.element
Try using: node.innerHTML and checking against that
is it me or post a question on stackoverflow and 20min after test testing I figure it.,...
the answer is that in the selectedContentWrap I already got list of nodes, all I need to do i compare , so a simple if for loop will fit.
To compare the names I just need to use .nodeName as that works cross browser ( correct me if I am wrong)
Some dev say that "dictionary of tag names and anonymous closures instead" - but couldn't find anything. If anyone has this library could you please post it to the question?
here is my code.
var node = selectedContentWrap;
console.log('node that is selectedwrapper', selectedContentWrap)
for (var i = 0; i < selectedContentWrap.length; i++) {
console.log('tag name is ',selectedContentWrap[i].nodeName);
var temptagname = selectedContentWrap[i].nodeName; // for debugging
if(selectedContentWrap[i].nodeName == 'B' ){
console.log('contains element B');
}
}

Prevent an undefined into one line code

Using document command there are some times which is not exist. Instead of using controls like document contains or type of into one if statement is it possible to make the control into one line and if the command doesn't exist take an NA like this:
document.querySelector('div#name span.fn').textContent || "NA";
You could do something like this:
(document.querySelector('div#name span.fn') || {}).textContent || "NA";
If the querySelector call evaluates to null, it will return the object, which won't have a textContent, so it will return NA.
Create a function for something like this.
function getTextContentOrDefault(selector, defaultValue) {
var element = document.querySelector(selector);
if (!element) return defaultValue;
if (!element.textContent) return defaultValue;
return element.textContent;
}
getTextContentOrDefault('div#name span.fn', 'NA');

JavaScript: querySelector Null vs querySelector

What is the main difference between these two methods of referencing?
What are the benefits of using one or the other? Also what kind of usage-case would they each be best suited to?
var selection = document.querySelector('.selector') !== null;
var selection = document.querySelector('.selector');
Is the former solely for browser legacy support?
The first one gets the reference and checks if the element exists, and saves this status as a boolean value in the variable. If the element exists, the variable contains true otherwise false.
You would use the first one if you only want to know if the element exists, but don't need the reference to it.
Example:
var selection = document.querySelector('.selector') !== null;
if (selection) {
alert('The element exists in the page.');
} else {
alert('The element does not exists in the page.');
}
The second one gets the reference and stores in the variable, but doesn't check if the element exists. If the element exists, the variable contains the reference to the element, otherwise the variable contains null.
You would use the second one if you need the reference to the element. If it's possible that the element doesn't exist in the page, you should check if the variable contains null before you try to do something with the reference.
Example:
var selection = document.querySelector('.selector');
if (selection !== null) {
alert('I have a reference to a ' + selection.tagName + ' element.');
} else {
alert('The element does not exists in the page.');
}
you could also do:
[].filter.call([document.querySelector('.single-selected-class')], item => item)
.forEach(item => item.blur());
The first statement contains a bool value depends on document.querySelector('.selector') is null or not
var selection = document.querySelector('.selector') !== null;
the second statement contains the actual value of document.querySelector('.selector');
var selection = document.querySelector('.selector');
You can try to avoid the conditional statement with:
var selection = document.querySelectorAll('.selector');
selection.forEach(function(item) {
alert(item);
});
Caution! querySelectorAll() behaves differently than most common JavaScript DOM libraries, which might lead to unexpected results
Source: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
I was developing a similar solution for CMS EFFCORE and came up with the following:
if (!Node.prototype.hasOwnProperty('querySelector__withHandler')) {
Object.defineProperty(Node.prototype, 'querySelector__withHandler', {
configurable: true,
enumerable : true,
writable : true,
value: function (query, handler) {
var result = this.querySelector(query);
if (result instanceof Node) {
handler(result);
}
}
});
}
document.querySelector__withHandler('a', function(link){
alert(link)
})

Using .length to check if an element exists in JQuery with concated array

Using the common 'if ID exist' method found here, is it still possible check for the existence of the ID when concating the ID with an array variable like below?
for (var i=0; i < lineData.length; i++)
{
optionData = lineData[i].split(",");
if ($("#" + optionData[0]).length)
{
$("#" + optionData[0]).text(optionData[1]);
}
}
When running this in debugging, if the concated $("#" + optionData[0]) ID doesn't exist it yeilds a result of 'undefined: undefined' and jumps to:
Sizzle.error = function( msg ) {
throw "Syntax error, unrecognized expression: " + msg;
in the JQuery code.
Is it proper code etiquette to use check for, and set, HTML ID's in this manner? Why does this not work in the popular 'exist' method? What can I do to fix it and make it skip ID's that don't exist using this type of ID concatenation with an array string?
http://jsfiddle.net/P824r/ works fine, so the problem is not where you think it is. Simplify your code and add in some checks. You're also not doing anything that requires jQuery, so I don't see how this is a jQuery question, but fine:
function handler(data, i) {
var optionData = data.split(","),
$element;
if (optionData[0] && optionData[1]) {
$element = $("#" + optionData[0]);
if ($element.length > 0) {
// omitting >0 as 'trick' causes JS coercion from number to boolean.
// there's literally no reason to ever do so: it's both slower and
// hides your intention to others reading your code
$element.text(optionData[1]);
}
} else { console.error("unexpected optionData:", optionData);
}
lineData.forEach(handler);
but we can do this without jQuery, since we're not really using for anything that we can't already do with plain JS, in the same number of calls:
function handler(data) {
var optionData = data.split(",");
if (optionData.length === 2) {
var id = optionData[0],
content = optionData[1],
element = document.getElementById(id);
// because remember: ids are unique, we either get 0
// or 1 result. always. jQuery makes no sense here.
if (element) {
element.textContent = content;
}
} else { console.error("unexpected input:", optionData);
}
lineData.forEach(handler);
(the non-jquery version unpacks the optionsData into separate variables for improved legibility, but the ultimate legibility would be to make sure lineData doesn't contain strings, but just contains correctly keyed objects to begin with, so we can do a forEach(function(data) { ... use data.id and data.content straight up ... }))
If you want to keep this jQuery-related, there's more "syntax sugar" you're not making use of:
// check for ID in array
jQuery.each(someArray,
function(index, value) {
var the_id = $(value).attr('id');
if ( the_id !== undefined && the_id !== false ) {
// This item has an id
}
});

Categories