translation of vanilla JavaScript to jQuery - javascript

Below is a JS function:
I'd like to update this so it uses jQuery but I am having difficulty figuring out how to translate it.
function pathContents(fileList) {
var list = document.createElement('ul');
for (file in fileList) {
var item = document.createElement('li');
item.appendChild(document.createTextNode(fileList[file]));
list.appendChild(item);
}
return list;
}
UPDATE:
Removing the call to pathContents() and replacing it with Malvolio's code - this is the browser output -
Why isn't it displaying the data as list items in an unordered list?

The jQuery equivalent "all-the-way" would be:
function pathContents(fileList) {
var $list = $('<ul/>');
$.each(fileList, function () {
$('<li/>').text(this).appendTo($list);
});
return $list;
}
The use of this inside $.each is often seen in jQuery code, but it is cleaner to use the function arguments instead:
$.each(fileList, function (_, file) {
$('<li/>').text(file).appendTo($list);
});
But the pure JavaScript way really is not that bad. For one, you cannot beat the performance of it.

you can try following :):
function pathContents(fileList) {
var list = $('<ul />');
for (file in fileList) {
list.append($('<li />').text(fileList[file]));
}
return list;
}
or you can return list.html();
And yes, as many users mentioned, you will have some performance loss compared to pure javascript

The modern version of your function would be
let pathContents =
fileList =>
$('<ul/>').append(fileList.map(file => $('<li/>').text(file)));
This version uses jQuery to create and append to DOM objects, the fat-arrow notation for functions, and the .map method on lists. It doesn't rely on the unreliable in operator and avoids the Bobby Tables exploit.
I kept your function and variable names, but I think you should consider more descriptive names.

For better performance only parse the HTML string at the very end:
function pathContents(fileList) {
var ul = '<ul>';
for( var file of fileList )
ul += `<li>${file}</li>`;
ul += '</ul>';
return $.parseHTML(ul);
;
}
console.log( pathContents([1,2,3])[0].outerHTML )
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
or as simple as:
function pathContents(fileList) {
var ul = '<ul><li>' + fileList.join('</li><li>') + '</li></ul>';
return $.parseHTML(ul);
}
By using $.parseHTML the parsed output will be stripped of any <script> tags. If you do want to keep them, pass true as the second argument for that method. See further discussion about this.
Please be careful when creating DOM from javascript: make sure the
input is sanitized (does not contain any malicious code).

Related

Selecting by text with Protractor

I am mostly familiar with java selenium, and I am new to both JS and Protractor. Lets say I am trying to click an option from a list of options with a common identifier..
var options = $('.options');
How could I get all elements with that common identifier, and then select one by its text? I can not do driver.findElements like I could in java since there is no reference to driver..
This is what I have tried so far but its not working and I think its due to my inexperience with JS
this.selectCompanyCode = function(companyCode) {
dropDownMenus[0].click();
var companyCodeOptions = $('[ng-bind-html="companyCode"]');
companyCodeOptions.filter(function (elem) {
return elem.getText().then(function text() {
return text === companyCode;
});
}).first().click();
};
Select all elements with common identifier: $$('.options'); That selects all elements with a class of .options -- equivalent of element.all(by.css('.options')). This returns an ElementArrayFinder. Also see .get() for how to choose an element by index from the ElementArrayFinder.
Find by text, you could use cssContainingText(css, text). For example,
var loginBtn = element(by.cssContainingText('button.ng-scope', 'Login'));
But if for some reason those are not providing the expected results, you can use .filter() (docs here) on an ElementArrayFinder to go through the array of elements and find an element based on a condition you specify. For example,
var allOptions = $$('.options');
allOptions.filter(function (elem) {
return elem.getText().then(function (text) {
return text === 'What you want';
});
}).first().click();
And, although I've never used regular Java Selenium (so I don't know if this is the same), but there is indeed a browser reference (and therefore findElements function): http://www.protractortest.org/#/api?view=ProtractorBrowser.
Hope it helps!
Edit:
Using your code:
this.selectCompanyCode = function(companyCode) {
// where is dropDownMenus defined? This has function no reference to it.
dropDownMenus.get(0).click(); // should be this
var companyCodeOptions = $$('[ng-bind-html="' + companyCode + '"]');
return companyCodeOptions.filter(function (elem) {
return elem.getText().then(function text() {
return text === companyCode;
});
}).first().click();
};
second edit:
Assuming company code is unique, you probably don't need to use filter. Try this:
this.selectCompanyCode = function(companyCode) {
dropDownMenus.get(0).click();
var companyCodeOptions = $('[ng-bind-html="' + companyCode + '"]');
return companyCodeOptions.click();
};
Use cssContainingText
element(by.cssContainingText(".option", "text")).click();
http://www.protractortest.org/#/api?view=ProtractorBy.prototype.cssContainingText

What methods or procedures need to be in place to append in jQuery a simple Java 'class' instance that represents a jQuery implementation?

I have this class in Javascript: call it Caption:
function Caption
{
var ...
function get...()
{ }
function set...(...)
{ ... }
return( { get...: get...
, set...: set...
});
}
This is only one component of a larger system and is part of an outer class called Filter. I would love to be able to when creating the jQuery for the object to be able to say:
tblFilter.append(getCaption())
which would get the Caption class instance variable and append the jQuery representation of it. Do I need to inherit from jQuery to make that happen? Like this?
function Caption
{
var ...
function get...()
{ }
function set...(...)
{ ... }
var that = jQuery();
that.get... = get...;
that.set... = set...;
return(that);
}
?
If that's true, what I'm not sure of is what function/method I need to write to produce the jQuery that is produced to be appended to the outer jQuery. Does this make sense and if so, what am I missing?
Edit:
Let me elaborate - Ok I'm creating my own version of a Data Table. Yes I know jQueryUI has but with this, I pass the data and it renders the data. There's a Filter component that really can't be created/constructed publicly but just accessed by a getFilter() method. Every time the Filter instance is changed, thanks to a home grown listener/observer/observable pattern, the filter is erased and re-rendered. As of now much of it is hard coded. When I first wrote it it was more loosely written as it was for a programming assignment to get a job and I did it within 2 days I had. Now that it's done I'm trying to implement it more generically into a library. When I get to appending the Caption and trying to make it render it based on the Caption object, I have no ID for a Caption or a parent object to remove. Ideally I'd love to be able to do:
var objDataTable = new DataTable(/*parameters*/);
$(/*parent selector/*).append(objDataTable);
I'm self taught so my Object Oriented Programming is a bit all over the place, but if I had a class, that I wanted to 'HTMLize' and insert values from into the dom, I would do it like this:
var Caption = {
'amount':10,
'word':'Hello!',
'getCaption': function(appendToObject){
var div = $('<div />');
var ul = $('<ul />');
var li = $('<li />', {
'text' : this.word
});
li.appendTo(ul);
var li2 = $('<li />', {
'text' : this.amount
});
li2.appendTo(ul);
ul.appendTo(div);
div.appendTo(appendToObject);
}
};
var caption_instance = Caption;
caption_instance.getCaption('#wrapper');
var second_caption = Caption;
second_caption.amount = 13;
second_caption.word = 'Goodbye';
caption_instance.getCaption('#wrapper');
You can see it in action here:
http://codepen.io/EightArmsHQ/pen/bVrapW
If you are including jQuery globally you don't need to pass anything to the function, you can just get going.
The important part here is the var xxx = $('<DOM_TAG />'); which lets you create elements to append to the DOM. This can be found here: http://api.jquery.com/jquery/#jQuery2
If I've misunderstood the question just let me know and I'll remove the answer.

jQuery.each iterating over list twice when there are three objects in it. Javascript

There are three objects inside plan_unit_list_items, but only two li are appended to my ul. Can anyone tell me why this might be?
var plan_unit_list_items = {!planUnitList}; // APEX METHOD
var openPlanUnitList = function (unitdiv) {
jQuery('div.plan_unit_dropdown').remove();
var plan_unit_dr = jQuery('<div>')
.addClass('plan_unit_dropdown')
.append('<ul>');
jQuery.each(plan_unit_list_items,
function (idx, val) {
jQuery('.plan_unit_dropdown ul').append(
jQuery('<li>')
.addClass('plan_unit_list_items')
.text(val.Name))
plan_unit_dr.appendTo(unitdiv);
})
}
(And I apologise if 'iterating' is the wrong terminology in the question)
If I understand your code, it looks like you are creating a ul and then trying to append lis to it, but you are using the following selector to select the ul from the DOM when it hasn't yet been added to the DOM until after the first iteration:
jQuery('.plan_unit_dropdown ul')
So on the first iteration, no appending happens. Since you already have access to the newly-created ul, why not just append directly to that rather than re-selecting it?
var openPlanUnitList = function (unitdiv) {
jQuery('div.plan_unit_dropdown').remove();
var plan_unit_ul = jQuery('<ul>'),
plan_unit_dr = jQuery('<div>')
.addClass('plan_unit_dropdown')
.append(plan_unit_ul);
plan_unit_dr.appendTo(unitdiv);
jQuery.each(plan_unit_list_items, function (idx, val) {
plan_unit_ul.append(jQuery('<li>')
.addClass('plan_unit_list_items')
.text(val.Name));
});
};

Testing function that creates a list of DOM components

I have a function which creates an Array of components. Each component is an outer div with a few inner divs.
function createDivs(quizQuestions) {
var returnElements = new Array();
$.each(quizQuestions.questions, function(i, val){
// create the div.
quizDiv = $('<div class="questionContainer radius">')
questionDiv = $('<div class="question"><b><span>QuestionText</span></b></div>');
quizDiv.append(questionDiv);
// Now change the question div text.
questionDiv.text = val.question;
answerDiv = $('<div class="answers">');
// ...
// ...
// Now the answers.
questionDiv.append(answerDiv);
returnElements[i] = quizDiv;
});
return returnElements;
I pass JSON such as:
{questions:[{"question":"Name the best Rugby team?",
"answers":["Leinster", "Munster", "Ulster", "Connaught"],
"correct_answer":"Leinster"},
{"question":"Name the best DJ?",
"answers":["Warren K", "Pressure", "Digweed", "Sasha"],
"correct_answer":"Leinster"}]};
I'd like to write a simpe unit test so that I could test the array of div returned made sense
Any tips?
Also, are my better to return a DOM component or just text? The latter would be easier to test.
Thanks.
Not sure exactly what you want to test but it is far more performant to create as much html in strings as you possibly can to reduce function calls. Also append is expensive so ultimately making one string for all the new content represented by the JSON will be the biggest performance gain.
In my opinion it also makes code more readable since fragments are in same order as the would be in html editor
Example(my preferece is creating an array of all the string fragments, concatenation also commonly used):
var newcontent = [];
$.each(quizQuestions.questions, function(i, val) {
newcontent.push('<div class="questionContainer radius">');
newcontent.push('<div class="question"><b><span>' + val.question + '< /span></b > < /div>');
$.each(val.answers, function(idx, answer) {
newcontent.push('<div class="answers">' + answer + '</div > ')
})
newcontent.push(' </div></div > ');
});
Then to add content to DOM:
$('#someDiv').append( newcontent.join(''));
disclaimer: Not fully checked for proper closing/nesting of tags.

jQuery .each help, I want to trim() all the strings in an array

I'm splitting a string into an array, then I want to remove the white space around each element. I'm using jQuery. I'm able to do this successfully with 2 arrays but I know it's not correct. How do I loop thru an array and trim each element so the elements keep that change. Thanks for any tips. Here is my working code using two array. Please show me the correct way to do this.
var arVeh = vehicleText.split("|");
var cleanArry = new Array();
$.each(arVeh, function (idx, val) {
cleanArry.push($.trim(this));
});
Cheers,
~ck in San Diego
You don't even really need the idx or val parameters. This appears to work on jsFiddle:
var cleanVehicles = [];
$.each(vehicleText.split("|"), function(){
cleanVehicles.push($.trim(this));
});
EDIT: Now that I've seen what you're really after, try using map:
var cleanVehicles = $.map(vehicleText.split("|"), $.trim);
I'm going to suggest not using the overhead of jQuery for a simple for-loop...
var arVeh = vehicleText.split("|");
for (var i = 0, l = arVeh.length; i < l; ++i) {
arVeh[i] = $.trim(arVeh[i]);
});
Alternatively, get rid of the whitespace from the beginning, and avoid the need for another loop at all.
var arVeh = $.trim(vehicleText).split(/\s*\|\s*/);
Without 'creating' an array in the javascript code (an array will nevertheless be created in memory)
vehicles = $.map(vehicleText.split("|"), function(e,i) { return $.trim(e) });
var my_arr = [' cats', 'dogs ', ' what '];
$.each(my_arr, function (id, val) {
my_arr[id] = $.trim(val);
});
console.log(my_arr);
This will trim the value and set it to the indexed item.
You don't have to use JQuery. Here is your vanilla solution:
testArray.map(Function.prototype.call, String.prototype.trim);
Function.prototype.call calls trim() on each of the elements of the testArray. As simple as that!
Could you not just do this?
var arVeh = vehicleText.split("|");
$.each(arVeh, function (idx, val) {
arVeh[idx] = $.trim(this);
});
//a simple function
function trimArray(dirtyArray){
$.map(dirtyArray.split("|"), function(idx, val){
return $.trim(this);
});
}
trimArray(vehicleArray);
should do the trick
Or you could use some of the awesome power of javascript and use array.prototype. I'm still a little new at using the .prototype of any object... so this isnt guaranteed to work (but it certainly can be done).
Array.prototype.trim = function (){
$.map(dirtyArray.split("|"), function(idx, val){
return $.trim(this);
});
}
someArray.trim()
You need these two jQuery functions:
1.) iterate through array element with ability to edit items:
http://api.jquery.com/jquery.map/
2.) remove blank spaces from beginning and end of a string:
http://api.jquery.com/jQuery.trim/
Use them this way:
array = $.map(array, function(value) { return value.trim();});
Check this JSFiddle:
https://jsfiddle.net/L00eyL4x/49/

Categories