Loop through JQuery array - javascript

I'm creating a self updating match/fixture script, which return data from a JSON Script which automatically updates. However the JSON script include 3 arrays live, upcoming and recent. How can i loop through all of these arrays instead of just matches[0] which is live? i've tried using loop, but it cant loop through the functions?
var lastLoadedMatch = 0,
ajaxInterval = 5000;
$(function() {
getMatches();
});
function getMatches(lastId) {
$.getJSON('data.json', function(resp) {
console.log(JSON.stringify(resp));
var matches = [resp.live, resp.upcoming, resp.recent];
if (lastId) {
matches[0] = matches[0].filter(
function(match) {
return match.id > lastId;
});
}
if (matches[0].length) {
$.each(matches[0], function(_, match) {
console.log([match.match_id,lastLoadedMatch ])
if (match.match_id > lastLoadedMatch) {
lastLoadedMatch = match.match_id
}
if ($.trim(match.game) == "lol") {
$('#part-1').append(matchHtml(this))
} else if ($.trim(match.game) == "counterstrike") {
$('#part-2').append(matchHtml(this))
} else if ($.trim(match.game) == "dota2") {
$('#part-3').append(matchHtml(this))
} else if ($.trim(match.game) == "hearthstone") {
$('#part-4').append(matchHtml(this))
}
});
}else{
}
setTimeout(function() {
getMatches(lastLoadedMatch);
}, ajaxInterval);
});
}

Just wrap your code in one more $.each that will iterate of your matches array:
var matches = [resp.live, resp.upcoming, resp.recent];
$.each(matches, function(_, match) {
if (lastId) {
match = match.filter(
function(match) {
return match.id > lastId;
});
}
if (match.length) {
$.each(match, function(_, match) {
...
or you can concatenate the arrays:
var matches = resp.live.concat(resp.upcoming, resp.recent);

Related

node_modules select2 replace wrappedMatcher with startMatcher

I'm trying to change the select2.julll.js file from node_modules Angular 6 project.
So far I found some ways to do that tho, nothing has worked for me, would you fave any suggestions of how I can replace wrappedMatcher with startMatcher in select2 file?
S2.define('select2/compat/matcher',[
'jquery'
], function ($) {
function oldMatcher (matcher) {
function wrappedMatcher (params, data) {
var match = $.extend(true, {}, data);
if (params.term == null || $.trim(params.term) === '') {
return match;
}
if (data.children) {
for (var c = data.children.length - 1; c >= 0; c--) {
var child = data.children[c];
// Check if the child object matches
// The old matcher returned a boolean true or false
var doesMatch = matcher(params.term, child.text, child);
// If the child didn't match, pop it off
if (!doesMatch) {
match.children.splice(c, 1);
}
}
if (match.children.length > 0) {
return match;
}
}
if (matcher(params.term, data.text, data)) {
return match;
}
return null;
}
return wrappedMatcher;
}
return oldMatcher;
});
Adding the following code to my select2.directives.ts has solved my problem
if (data.text.toString().toLowerCase().indexOf(params.term) > -1 &&
!!data.text.toString().toLowerCase().startsWith(params.term.toString().toLowerCase())) {
var modifiedData = $.extend({}, data, true);
// modifiedData.text += ' (matched)';
// You can return modified objects from here
// This includes matching the `children` how you want in nested data sets
return modifiedData;
}

Protractor- Retrieve value of global array in a function

I am trying to push array content in a global defined empty array & then retrieve its contents inside another function.
Below is the code which i tried:
describe('My Test', function() {
var arrayf3=[];
var indexf3='not found';
it('Test starts', function() {
browser.ignoreSynchronization = true;
browser.get('https://www.w3schools.com/angular/');
var elm = element(by.id('leftmenuinner')).all(By.css('[target="_top"]'));
elm.count().then(function(count) {
Methods.pushToArray(0, count, elm);
})
var texttocheck='Data Binding';
Methods.getIndex(0, arrayf3.length, arrayf3, texttocheck);
console.log('Text content of global array is ' + arrayf3);
console.log('index of the array number having texttofind is ' + indexf3);
})
var Methods = {
getIndex :function (i, max, array, texttocheck) {
if (i < max) {
console.log('text[' + i + '].indexOf = ' + array[i].indexOf(texttocheck))
if (array[i].indexOf(texttocheck) > 0) {
indexf3 = i;
} else {
Methods.getIndex(i + 1, max, array, texttocheck);
}
}
},
pushToArray :function (i, max, elm) {
if (i < max) {
elm.get(i).getText().then(function(tmpText) {
console.log("The array "+tmpText);
arrayf3.push(tmpText);
})
Methods.pushToArray(i + 1, max, elm);
}
},
}
});
Problem is i am getting null values for below placeholder values:
Text content of global array is
index of the array number having texttofind is
I want the array value copied in this global empty array to be used & displayed in the same it block function 'Test starts'
Protractor's element.all inherently knows how to getText() on each of the elements and return the values as an array.
it('Test starts', function() {
browser.ignoreSynchronization = true;
browser.get('https://www.w3schools.com/angular/');
var getIndexOfElementByPartialText = function(inputText) {
return element(by.id('leftmenuinner')).all(by.css('[target="_top"]')).getText().then(function(values) {
var indexNumber;
values.forEach(function(value, index) {
if (new RegExp(inputText).test(value)) {
if (indexNumber === undefined) {
indexNumber = index;
} else {
throw new Error('multiple elements match the input text');
}
}
});
if (indexNumber === undefined) {
throw new Error('no elements match the input text');
} else {
return indexNumber;
}
});
});
expect(getIndexOfElementByPartialText('thing1').toBe(1);
expect(getIndexOfElementByPartialText('thing2').toBe(2);
});
Edited the answer to provide it in terms of a re-usable function.

AngularJS Pass variables into looped asynchronous callback

I have a function that loops through in indeterminate number of items and does an asynchronous call on each one to get additional data (the content of html template files). The callback does some checking. The resulting function should be thenable. $q is injected earlier, this code is part of a factory.
function searchHelpTopics(topics, searchPhrase) {
if (topics == null || topics.length == 0) return "No search results";
var results = [];
var promises = [];
for (var i = 0; i < topics.length; i++) {
var templateURL = topics[i].URL;
var topic = topics[i];
if (topics[i].HelpTopicId != "Search") {
var promise = $templateRequest(templateURL).then(function (template) {
var text = HTMLToText(template, true);
// do the search
if (text.indexOf(searchPhrase) > -1) {
if (text.length > 50) text = text.substring(0, 50);
var result = {};
result.title = topic.Title;
result.excerpt = text;
result.helpID = topic.HelpTopicID;
results.push(result);
}
});
promises.push(promise);
}
}
return $q.all(promises).then(function () {
return results;
})
The problem here is that the for loop does not wait for the callbacks obviously and so the topic being used by the callback is not the correct one. I need a way to pass topic into the callback on each loop.
Because JS has only function scope you can rewrite your code to use function instead of 'for' loop (which is usually better).
To do that you can use JS built-in forEach (which is available starting from version 1.6 so almost for all browsers) or good functional style libraries like underscore.js or lodash.js.
Or even better - to use Array.map and Array.filter - see the code
function processTemplate(topic, template) {
var text = HTMLToText(template, true);
// do the search
if (text.indexOf(searchPhrase) < 0) {
return;
}
if (text.length > 50) {
text = text.substring(0, 50);
}
return {
title: topic.Title,
excerpt: text,
helpID: topic.HelpTopicID
};
}
function searchHelpTopics(topics, searchPhrase) {
if (!topics || topics.length === 0) {
return "No search results";
}
var promises = topics
.filter(function(topic) { return topic.HelpTopicId !== "Search"; })
.map(function(topic) {
return $templateRequest(topic.URL).then(processTemplate);
});
return $q.all(promises)
.then(function (results) {
return results.filter(function (result) {
return result; // filters out 'undefined'
});
});
}
The is not a complete solution but enough to indicate how it works
somefactory.getHelpTopics().then(function (topics) {
somefactory.searchHelpTopics(topics, searchText).then(function (searchResults) {
vm.searchResults = searchResults;
vm.helpID = "Search";
});
});
--- some factory functions ----
function searchHelpTopics(topics, searchPhrase) {
if (!topics || topics.length === 0) return "No search results";
var promises = topics
.filter(function (topic) { return topic.HelpTopicId !== "Search"; })
.map(function (topic) {
return $templateRequest(topic.URL).then(function (template) {
return searchHelpTemplate(template, topic, searchPhrase);
});
});
return $q.all(promises).then(function (results) {
return results.filter(function (result) {
return result; // filters out 'undefined'
});
});
}
function searchHelpTemplate(template, topic, searchPhrase) {
var text = HTMLToText(template, true);
// do the search
if (text.indexOf(searchPhrase) < 0 && topic.Title.indexOf(searchPhrase) < 0) {
return;
}
if (text.length > 50) {
text = text.substring(0, 50);
}
return {
title: topic.Title,
excerpt: text,
helpID: topic.HelpTopicId
};
}

NodeJS arr.splice() not removing from array

Using the following code, I'm supposed to check if the arrays (ai, jq, and rz)
has users with the same 'interest' and if so, remove that user from all arrays.
But it seems that the .splice() method is not be working as I log the arrays and they still contain that user. Any ideas?
Code:
function joinQueue(sid, interests, fn) {
var exists = false;
interests.forEach(function(interest) {
interest = interest.toLowerCase();
getTable(interest.charAt(0), function(table) {
table.forEach(function(data) {
if(data.interest == interest && !exists) {
var aa = 0;
ai.forEach(function(a) {
if(a.sid == data.sid) { ai.splice(aa, 1); console.log(ai);}
aa++;
});
var jj = 0;
jq.forEach(function(j) {
if(j.sid == data.sid) { jq.splice(jj, 1); console.log(jq); }
jj++;
});
var rr = 0;
rz.forEach(function(r) {
if(r.sid == data.sid) { rz.splice(rr, 1); console.log(rz); }
rr++;
});
fn(data);
exists = true;
}
});
});
});
if(!exists) {
interests.forEach(function(interest) {
interest = interest.toLowerCase();
getTable(interest.charAt(0), function(table) {
table.push({'sid': sid, 'interest': interest});
});
});
fn();
}
}
Here's a bit safer version that uses a backwards for loop traversal to avoid issues when the current item is removed.
function joinQueue(sid, interests, fn) {
var exists = false;
interests.forEach(function(interest) {
interest = interest.toLowerCase();
getTable(interest.charAt(0), function(table) {
table.forEach(function(data) {
if(data.interest == interest && !exists) {
var sid = data.sid;
var sliceItOff = function(arr) {
for (var i = arr.length - 1; i >= 0; i--) {
if(arr[i].sid == sid) {
arr.splice(i, 1);
}
}
};
sliceItOff(ai);
sliceItOff(jq);
sliceItOff(rz);
fn(data);
exists = true;
}
});
});
});
if(!exists) {
interests.forEach(function(interest) {
interest = interest.toLowerCase();
getTable(interest.charAt(0), function(table) {
table.push({'sid': sid, 'interest': interest});
});
});
fn();
}
}
[Untested]. It is difficult to establish whether it makes any difference without access to testable code (input data and some other variables are missing).
It is best to avoid to add or remove items to an array as you are looping over it. Best is to loop over a clone of the array rather than the array itself. Try with the code below to see if it makes any difference.
function joinQueue(sid, interests, fn) {
var exists = false;
interests.forEach(function(interest) {
interest = interest.toLowerCase();
getTable(interest.charAt(0), function(table) {
table.forEach(function(data) {
if(data.interest == interest && !exists) {
var sid = data.sid;
var sliceItOff = function(arr) {
arr.slice(0).forEach(function(d, i) {
// [warning]. if more than one item meets the condition (d.sid == sid),
// then you are likely to remove an item at the wrong index.
// A better approach is to build a new array rather than modify the old one
if(d.sid == sid) { arr.splice(i, 1); console.log(arr); }
});
};
sliceItOff(ai);
sliceItOff(jq);
sliceItOff(rz);
fn(data);
exists = true;
}
});
});
});
if(!exists) {
interests.forEach(function(interest) {
interest = interest.toLowerCase();
getTable(interest.charAt(0), function(table) {
table.push({'sid': sid, 'interest': interest});
});
});
fn();
}
}

Add space between numbers/digits and letters/characters

I have a code like this
(function($, window, document, undefined) {
$.fn.quicksearch = function (target, opt) {
var timeout, cache, rowcache, jq_results, val = '', e = this, options = $.extend({
delay: 100,
selector: null,
stripeRows: null,
loader: null,
noResults: '',
bind: 'keyup',
onBefore: function () {
return;
},
onAfter: function () {
return;
},
show: function () {
this.style.display = "";
},
hide: function () {
this.style.display = "none";
},
prepareQuery: function (val) {
return val.toLowerCase().split(' ');
},
testQuery: function (query, txt, _row) {
for (var i = 0; i < query.length; i += 1) {
if (txt.indexOf(query[i]) === -1) {
return false;
}
}
return true;
}
}, opt);
this.go = function () {
var i = 0,
noresults = true,
query = options.prepareQuery(val),
val_empty = (val.replace(' ', '').length === 0);
for (var i = 0, len = rowcache.length; i < len; i++) {
if (val_empty || options.testQuery(query, cache[i], rowcache[i])) {
options.show.apply(rowcache[i]);
noresults = false;
} else {
options.hide.apply(rowcache[i]);
}
}
if (noresults) {
this.results(false);
} else {
this.results(true);
this.stripe();
}
this.loader(false);
options.onAfter();
return this;
};
this.stripe = function () {
if (typeof options.stripeRows === "object" && options.stripeRows !== null)
{
var joined = options.stripeRows.join(' ');
var stripeRows_length = options.stripeRows.length;
jq_results.not(':hidden').each(function (i) {
$(this).removeClass(joined).addClass(options.stripeRows[i % stripeRows_length]);
});
}
return this;
};
this.strip_html = function (input) {
var output = input.replace(new RegExp('<[^<]+\>', 'g'), "");
output = $.trim(output.toLowerCase());
return output;
};
this.results = function (bool) {
if (typeof options.noResults === "string" && options.noResults !== "") {
if (bool) {
$(options.noResults).hide();
} else {
$(options.noResults).show();
}
}
return this;
};
this.loader = function (bool) {
if (typeof options.loader === "string" && options.loader !== "") {
(bool) ? $(options.loader).show() : $(options.loader).hide();
}
return this;
};
this.cache = function () {
jq_results = $(target);
if (typeof options.noResults === "string" && options.noResults !== "") {
jq_results = jq_results.not(options.noResults);
}
var t = (typeof options.selector === "string") ? jq_results.find(options.selector) : $(target).not(options.noResults);
cache = t.map(function () {
return e.strip_html(this.innerHTML);
});
rowcache = jq_results.map(function () {
return this;
});
return this.go();
};
this.trigger = function () {
this.loader(true);
options.onBefore();
window.clearTimeout(timeout);
timeout = window.setTimeout(function () {
e.go();
}, options.delay);
return this;
};
this.cache();
this.results(true);
this.stripe();
this.loader(false);
return this.each(function () {
$(this).bind(options.bind, function () {
val = $(this).val();
e.trigger();
});
});
};
}(jQuery, this, document));
I try to figure out where and how I can make a split/add space between numbers and letters. Cause some people type for example "ip1500" and the script cant match the input with an element that is like "ip 1500". My problem ist that Im a js beginner.
I was trying and trying but i cant get it work. I also tried this
I found this spot and I think it can be done here where the everything get splitted by an " " (space):
prepareQuery: function (val) {
return val.toLowerCase().split(' ');
},
Would be very nice if somebody can help me.
If you want "123abc345def" to "123 abc 345 def". The replace function may help. The code is like this.
var str = "123abc345def";
str = str.replace(/(\d+)/g, function (_, num){
console.log(num);
return ' ' + num + ' ';
});
str = str.trim();
The code you linked didn't work mainly because it's using a different programming language to javascript. In theory, it should work, but javascript does not support regular expression lookbehinds (at this present time)..
Instead, I have re-wrote that fragment of code:
prepareQuery: function (val) {
function isNotLetter(a){
return (/[0-9-_ ]/.test(a));
}
var val=val.toLowerCase().split("");
var tempArray=val.join("").split("");
var currentIndex=1;
for (var i=0;i<val.length-1;i++){
if (isNotLetter(val[i]) !== isNotLetter(val[i+1])){
tempArray.splice(i+currentIndex, 0, " ");
currentIndex++;
}
}
return tempArray.join("");
}
Since you're new to javascript, I'm going to explain what it does.
It declares a function in prepareQuery to check whether or not a string contains a letter [this can be moved somewhere else]
It then splits val into an array and copies the content of val into tempArray
An index is declared (explained later)
A loop is made, which goes through every single character in val
The if statement detects whether or not the current character (val[i] as set by the loop) is the same as the character next to it (val[i+1]).
IF either one are different to the other (ie the current character is a letter while the next isn't) then a space is added to the tempArray at that "index"
The index is incremented and used as an offset in #6
The loop finishes, joins the "array" into a string and outputs the result.
DEMO:
http://jsbin.com/ebitus/1/edit
(JSFiddle was down....)
EDIT:
Sorry, but I completely misinterpreted your question... You failed to mention that you were using "quicksearch" and jQuery. In that case I'm assuming that you have a list of elements that have names and you want to search through them with the plugin...
A much easier way to match the user's query (if there is no space) is to strip the space from the search table along with the query itself - though original reverse method will work (just not as efficiently) [aka: expanding the user's query]
In this case, stripping the space from both the search table and user input would be a better method
prepareQuery: function (val) {
return val.toLowerCase().replace(/ /ig,'').split(" ");
},
testQuery: function (query, txt, _row) {
txt=txt.toLowerCase().replace(/ /ig,'');
for (var i = 0; i < query.length; i += 1) {
if (txt.indexOf(query[i]) === -1) {
return false;
}
}
return true;
}
DEMO:
http://jsfiddle.net/q9k9Y/3/
Edit 2:
It seems like your real intent is to create a fully functioning search feature on your website, not to just add spaces between letters and numbers. With this, I suggest using Quicksilver. I would love to work out an algorithm to extend quickSearcher but at the current time I cannot (timezones). Instead, I suggest using Quicksilver
http://jsbin.com/oruhet/12/

Categories

Resources