Can this javascript be reduced? - javascript

I was curious to see if anyone knew a of a way to reduce this javascript code:
var channels;
channels = [];
$('li.suggestions article').each(function() {
return channels.push($(this).data('channel-id'));
});
It's really simple -- the snippet just initializes an array called "channels", iterates over some DOM elements and collects their "data-channel-id" attribute, adding it to that array.
It is something I do a lot and it would be great to have this snippet simplified further -- I'd accept a CoffeeScript answer too if there is a nice solution.

var channels = $('li.suggestions article').map(function() {
return $(this).data('channel-id');
}).get();

Related

Show only the latest 3 results using a loop in JavaScript

I have a script that pulls in results and displays it on my site. I want to display only the last three results that are being pulled instead of everything. So the latest results are Test2, Test1 and then Office 365 Planned Service.
Here are all the results being pulled:
Here is my JavaScript code:
$(document).ready(function(){
$pnp.setup({
baseUrl: "https://fh126cloud.sharepoint.com/TrainingResourceCenter/O365Training"
});
$pnp.sp.web.lists.getByTitle("O365RoadMap").items.orderBy("Created", false).get().then(function(items) {
console.log(items);
var result = items.map(item => {
return {
Title: item.Title,
Description: item.Description,
Link: item.Link
}
});
var $table = roadMapDisplay(result);
console.log($table);
$('#title').html($table);
});
function roadMapDisplay(items) {
var table = $('<container/>');
items.forEach(item => {
table.append(`${item.Title}`);
table.append(`<div style="text-indent: 10px">${item.Description.slice(0, -200)}...</div>`);
table.append('<br/>');
});
return table;
}
});
How could I throw a loop onto that function? I've tried so many different ways and have come short.
Thanks all in advance!
The following is specific to arrays. However, it appears there's a $pnp-specific answer which it seems to me should be more efficient.
Assuming your current code works (showing the full list), you can grab just the first three entries in items like this:
items = items.slice(0, 3);
...or the last three like this:
items = items.slice(-3);
I am guessing that $pnp is the PnP JavaScript Library With jQuery In SharePoint based on a quick search online.
I don't know too much about PnP; however, I noticed this documentation in https://github.com/SharePoint/PnP-JS-Core/wiki/Working-With:-Items:
// use odata operators for more efficient queries
$pnp.sp.web.lists.getByTitle("My List").items.select("Title", "Description").top(5).orderBy("Modified", true).get().then((items: any[]) => {
console.log(items);
});
As you can see they are using "top(5)"; therefore, you could change the order, so you get first the last elements, then use top(3) to obtain those three records you wish to display.
Since $pnp seems to follow a chain pattern, I wonder if you could apply again the order method after obtaining the top(3).
To keep two arrays:
var items = [1,2,3,4,5,6]
var n = 3
var remainingArray = items.splice(0, items.length-n);
console.log(remainingArray)//<--first n elements
console.log(items)//<--last n elements
I think your are looking for this. if our query always returns top three items then why we explicitly goes to javascript?
$pnp.sp.web.lists.getByTitle("O365RoadMap").items.top(3).orderBy("Created", false).get().then(function(items) {
console.log(items);
});
you can get more knowledge from here

Unusual JavaScript for loop with xml in Blockly

I'm working on a project with Google's Blockly, but parts of the documentation are incomprehensible. Can someone help me understand the end condition of the following for loop (xml = allXml[i])?
var allXml = Blockly.Xml.workspaceToDom(workspace);
var allCode = [];
for (var i = 0, xml; xml = allXml[i]; i++) {
var headless = new Blockly.Workspace();
Blockly.Xml.domToWorkspace(headless, xml);
allCode.push(Blockly.JavaScript.workspaceToCode(headless));
headless.dispose();
}
I imagine the loop will exit when allXml[i] is undefined, but how can you iterate through an XML object like this? It seems to always be returning undefined and skipping the loop entirely.
Thanks for you help
Definitions for most of the function can be found at https://code.google.com/p/blockly/source/browse/trunk/core/xml.js?r=1614
And the doc page I pulled this from is https://developers.google.com/blockly/custom-blocks/code-structure?hl=en
I could not find this code in the repo on github, so I guess it is a bit older example in the docs.
But if you will have a look at the Blockly.Xml.workspaceToDom() function's implementation, you will see a very similar thing there.
var blocks = workspace.getTopBlocks(true);
for (var i = 0, block; block = blocks[i]; i++) {
var element = Blockly.Xml.blockToDom_(block);
//...
xml.appendChild(element);
}
The idea here is to iterate over all branches of code. The top block has no top connection (it starts a new branch). The getTopBlocks() returns an array {!Array.<!Blockly.Block>}.
Considering that the documentation is showing it in a section about parallel execution, I think it will be related to the fact, that you can have more unconnected branches of code... and the exact implementation just changed over time.
As per the code, return type of Blockly.Xml.workspaceToDom(workspace) is {!Element}.
It basically returns a DOM node created using goog.dom.createDom('xml');. And for each top level block it is appending a DOM node to it.
So basically the code snippet in question is looping through all the DOM nodes corresponding to the top level blocks.

AngularJS soltuion to determining if any element in array1 exists in array2

I am working on an angularJS widget (my first) and I currently am looking for an angularJS solution to my problem.
Basically I have one array containing a list of string values.
var array1 = [
"Need to Know",
"Test Category 2",
"News"
];
and another array containing another list of string values
var array2 = [
"need to know",
"release notes",
"NEWS"
];
I need a true statement if any element from one array matches any element from the other array. The result also needs to be case insensitive.
Here is my current solution and works great.
angular.module("myWidget", function(...){
// angular code here
})
.service('arrayService', function() {
function arrayToLowerCase(array) {
return array.join("~!~").toLowerCase().split("~!~");
}
function arrayElementIsInArray(array1, array2) {
for (var i in array1) {
if (array2.indexOf(array1[i]) >= 0) {
return true;
}
}
return false;
}
function arrayCompare(array1, array2) {
return arrayElementIsInArray(arrayToLowerCase(array1), arrayToLowerCase(array2));
}
return {
arrayToLowerCase: arrayToLowerCase,
arrayElementIsInArray: arrayElementIsInArray,
arrayCompare: arrayCompare
};
})
the problem is my javascript coders (I primary work in c#) feel there is a more angularJS way to do this but they have brought nothing to the table as a definitive solution. It was suggested that the $filter module might be useful but I didn't see how it would exactly solve my problem.
If I already have the best solution, then awesome. If not please let me know what you think and lets go from there.
Thanks in advance.
EDIT: In response to some of the answers, I felt that I might have misinterpreted my request. What I am asking is there a built in function that angular provides that does this out of the box?
After researching this a bit more; the $filter Module will probably do it with a custom comparater implemented but that seems like way overkill for what I am looking for.
The current responses are all good stuff though. Thanks again!
Absolutely nothing to do with Angular. This is plain data structures and data manipulation. To say there should be a more AngularJS way of doing it would be like saying there should be a more MVC way to add two numbers.
Angular provides no basic data structures and utility set of functions beyond what is available in your browser's native list of array functions, which is different depending on which ECMAScript standard the browser supports.
You may want to look into a library like Lo-Dash for stuff like this (which you can use right along with Angular with no problems) as it's preferable to have proven code for these kind of data manipulations than to constantly have to debug your own.
With Lo-Dash, and remembering the requirement for case-insensitivity:
var array1Lowered = _.map(array1, function (value) { return value.toLowerCase(); });
var anyMatchesBool = _.any(array2, function (value) {
return _.contains(array1Lowered, value);
});
Note that I'm making the assumption that there will be no non-string items in either array.
Lo-Dash normalizes the API so you don't need to worry about what functions each browswer supports. If there's a native function, Lo-Dash will use it because it's faster. If not, Lo-Dash provides an all-JavaScript implementation.
Try this on for size. To me this really has nothing to do with Angular
(function(array1, array2) {
var tlc = function(a) { return a.toLowerCase(); };
array2 = array2.map(tlc);
array1 = array1.map(tlc);
return array1.filter(function(n) {
return array2.indexOf(n) != -1;
}).length > 0;
})(array1, array2);
Using native functions...
var intersection = array1.filter(function(n) {
return array2.indexOf(n) != -1
});
With help from Simplest code for array intersection in javascript

Using a for loop iterator to shorten a function

I'm trying to shorten a 2.5k line function into something far more manageable using a few for loops. I've managed to stifle off all syntax errors after a lot of changes. However what was an originally extremely long but working function, has now turned into a much shorter but broken function. Can someone explain what I'm doing wrong.
This is the essence of what I'm trying to do:
function countryChange() {
//Blank auto complete box
for(var i=0; i<30; i++){
for(var q=5; q<7; q++){
for(var u=0; u<3; u++){
$("#_Q6_Q".concat(toString(i),"_Q", toString(q), "_Q0_Q", toString(u))).val('');
};
};
$("#_Q6_Q".concat(toString(i),"_Q4_Q0_Q0")).val('');
};
The function goes on a bit more, but everything is essentially a repetition, using for loops to generate a series of numbers which is then put into a few statements.
Without the for loops there are 30*3*3 variations of the _Q6_Q#_Q#_Q0_Q# which all have to be used and reused several times.
Also it might be worth noting that this is to use the JQuery AutoComplete widget:
http://api.jqueryui.com/autocomplete/#option-source
I wrote the previous 2.5k line script with Python which I'm more comfortable with and could generate all the large repetitive could with.
Fixed for now: had to change toString() to String(). Although some have mentioned that that isn't needed at all.
i suggest you split the problems, and create the numbers you'll later crunch within an array, and then define what will be the crunching function, then crunch the array :
function createArray () {
var res=[];
var i,q,u;
for(i=0; i<30; i++){
for(q=5; q<7; q++){
for(u=0; u<3; u++) {
res.push([i:i, q:q, u:u]);
};
};
};
}
// just build it once and store it
var myIndexes = createArray();
After that the processing can be done with one forEach for all your loops.
myIndexes.forEach(resetAutoCompleteComboBox);
with :
function resetAutoCompleteComboBox(a) {
var i=toString(a.i);
var q=toString(a.q);
var u=toString(a.u);
$("#_Q6_Q" + i + "_Q" + q + "_Q0_Q" + u)).val('');
}
If you take advantage of the similarity of the processing functions, you might also be able to do some other useful code factorisation.
Might be better to use jQuery's built in sizzle selectors:
function countryChange() {
$("[id^='_Q6_Q'],[id^='_Q'], [id^='_Q0_Q'], [id^='_Q4_Q0_Q0']").val('');
};
You can also do wildcards and partial matches if you like.
Here's the selectors reference guide: http://api.jquery.com/category/selectors/

Javascript: Get arrays based on dropdown selection

ok. I have a dropdown. well call it dropdownA. I have several arrays already fashioned, that i want to loop through, and put each individual value out onto the page into it's own input field, based on the selection in the dropdown. I know how to put together the loop to get the values out onto the page. anyway, here is the meta code.
meta1array=new Array('','','','','','');
meta2array=new Array('','','','','','');
meta3array=new Array('','','','','','');
function metacode(id){
{
var a=get.the.dd.selIndex;
var b=get.the.dd.options[a].value; //comes back as 'meta1'. other opts are meta2, meta3
var c=b+'array';
for(i=0;i<c.count;i++)
{
loop here to popout values
}
}
i have looked everywhere, and i haven't come up with anything. I also admit that my brain is starting to mushify from a few weeks straight of coding, and this is the first time i have come across this. so, please. i would be greatful for any help.
Global variables are members of the window object.
var c = window[b + 'array'];
It might be wise to make your arrays members of some other object though, for tighter scoping (avoid cluttering the global namespace).
metaobject = {
meta1array: ['','','','',''],
meta2array: ['','','','',''],
meta3array: ['','','','','']
};
// snip
var arr = metaobject[b + 'array'];
for(var i=0;i<arr.length;i++) {
//do work
}
Check out the fiddle using jquery here.

Categories