Break for loop inside closure - javascript

for (var e = 0; e < markers.length; e += 1) {
(function (e, markers, latLngBounds) {
if (latLngBounds.contains(markers[e])) {
updatePrompt("Marker is contained");
// Break for loop
}
})();
}
In the example above, after the updatePrompt method is invoked how can I break out of the loop containing the closure?

var broken = false;
for (var e = 0; e < markers.length; e += 1) {
if (broken) {
break;
} else {
(function (e, markers, latLngBounds) {
if (latLngBounds.contains(markers[e])) {
updatePrompt("Marker is contained");
broken = true;
}
})();
}
}
A little verbose, but you get the point.
This could also be done with Array.some in modern browsers
markers.some(function(marker) {
if (latLngBounds.contains(marker)) {
updatePrompt("Marker is contained");
return true;
}
return false;
});

not sure if i get you correct, but if you want to break the loop set
e= markers.length;
The loop will not continue after this statement

Another way:
for (var e = 0; e < markers.length; e += 1) {
if ((function (e, markers, latLngBounds) {
if (latLngBounds.contains(markers[e])) {
updatePrompt("Marker is contained");
return 1;
}
return 0;
})())
break;
}

Related

javascript events not apply in loop

Hi I'm trying to add some events to my page with a loop. this is my code
elements = $(".my-elements")
var i;
for (i = 0; i < elements.length; i++) {
e = elements[i];
document.addEventListener('scroll', event => {
if( inViewport(e) ) {
$(e).css({opacity: 1.0})
}
})
}
But after running the code, only the last event is applied, and previous events have no effect.
what's the problem?
Try this:
elements = $(".my-elements")
var i;
for (i = 0; i < elements.length; i++) {
function() {
var e = elements[i];
document.addEventListener('scroll', event => {
if( inViewport(e) ) {
$(e).css({opacity: 1.0})
}
})
}()
}
i think the method is running synchronously,
try to put it into an [async method][1], await for the function inside it and return a promise in each iteration.
it will stop the execution of the async function until one iteration is completed
like-
async function myEvent(){
elements = $(".my-elements")
var i;
for (i = 0; i < elements.length; i++) {
await function() {
return new Promise((resolve,reject)=>{
var e = elements[i];
document.addEventListener('scroll', event => {
if( inViewport(e) ) {
$(e).css({opacity: 1.0})
resolve();
}else{
resolve();
}
})
})
}
}
}
if there's an error in snippet you can correct it but take my point of going async.
[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

Changing <this> in object literal

I'm creating an object literal and I want to use the reserved word "this". The problem I'm having is that the "this" points to the window object in an object literal. I know the this points to the current object when used in a constructor function. Is there a way to override it so that "this" points to my object literal?
main = {
run: function()
{
var elements = [];
var allElements = document.querySelectorAll("*");
for(var i = 0; i < allElements.length; i++)
{
if(allElements[i].nodeType != 3)
{
elements.push(allElements[i]);
}
}
for(var i = 0; i < elements.length; i++)
{
// Doesn't work
// this.parseElement(elements[i]);
// Works
main.parseElement(elements[i]);
}
},
parseElement: function(e)
{
// Unimportant code
}
}
(function()
{
main.run();
})();
The thing you claim works in your question doesn't work:
var main = {
run: (function()
{
var elements = [];
var allElements = document.querySelectorAll("*");
for(var i = 0; i < allElements.length; i++)
{
if(allElements[i].nodeType != 3)
{
elements.push(allElements[i]);
}
}
for(var i = 0; i < elements.length; i++)
{
// Doesn't work
// this.parseElement(elements[i]);
// Works
main.parseElement(elements[i]);
}
})(),
parseElement: function(e)
{
// Unimportant code
}
};
<div></div>
Fundamentally, you cannot refer to the object being constructed from within the object initializer. You have to create the object first, because during the processing of the initializer, while the object does exist no reference to it is available to your code yet.
From the name run, it seems like you want run to be a method, which it isn't in your code (you've edited the question now to make it one). Just remove the ()() around the function:
var main = {
run: function() {
var elements = [];
var allElements = document.querySelectorAll("*");
for (var i = 0; i < allElements.length; i++) {
if (allElements[i].nodeType != 3) {
elements.push(allElements[i]);
}
}
for (var i = 0; i < elements.length; i++) {
this.parseElement(elements[i]);
}
},
parseElement: function(e) {
console.log("Parsing " + e.tagName);
}
};
main.run();
<div></div>
Since this is set by how the function is called for normal functions, if you want run to be bound to main so that it doesn't matter how it's called, using main instead of this is the simplest way to do that in that code.
But if you don't want to use main, you could create a bound function:
var main = {
run: function() {
var elements = [];
var allElements = document.querySelectorAll("*");
for (var i = 0; i < allElements.length; i++) {
if (allElements[i].nodeType != 3) {
elements.push(allElements[i]);
}
}
for (var i = 0; i < elements.length; i++) {
this.parseElement(elements[i]);
}
},
parseElement: function(e) {
console.log("Parsing " + e.tagName);
}
};
// Bind run
main.run = main.run.bind(main);
// Use it such that `this` would have been wrong
// if we hadn't bound it:
var f = main.run;
f();
<div></div>
Just as a side note, we can use Array.prototype.filter and Array.prototype.forEach to make that code a bit more concise:
var main = {
run: function() {
var allElements = document.querySelectorAll("*");
var elements = Array.prototype.filter.call(allElements, function(e) {
return e.nodeType != 3;
});
elements.forEach(this.parseElement, this);
},
parseElement: function(e) {
console.log("Parsing " + e.tagName);
}
};
// Use it
main.run();
<div></div>
That assumes that parseElement only ever looks at the first argument it's given (since forEach will call it with three: the entry we're visiting, its index, and the object we're looping through).

How to use function outside $scope ( error: function isn't defined)

I have a rzslider which takes in true or false for disabled. I want disable to be true based on a function. So I want to make it disabled:$scope.truthy
I have a function called checkDupsName() checkDupsName should return true if there is a duplicate, false otherwise. I set my $scope.truthy variable to be true if the function returns true but the issue is, when I call it outside this function ( in my slider), it's ALWAYS false.
$scope.checkDupsName = function(Mylist) {
var i, j, n;
n = Mylist.length;
for (i = 0; i < n; i++) {
for (j = i + 1; j < n; j++) {
if (Mylist[i] === Mylist[j]) {
return true;
}
}
}
return false;
};
$scope.truthy=false;
$scope.nameList = [];
var Types = [];
$scope.loadRuleList = function() {
PrioritizeService.getData($scope.prioritizeURL).
then(function(response) {
if (response) {
Types = response;
}
for (var k = 0; k < Types.length; k++) {
$scope.nameList.push(Types[k].name);
}
if($scope.checkDupsName($scope.nameList)) {
$scope.truthy=true;
}
};
$scope.slider = {
value: 1,
options: {
floor: 0,
ceil: 3,
showTicks: true,
showTicksValues: true,
disabled:$scope.truthy
}
};
You are defining it inside of your function that is being called by then. You should move it outside and make it a function defined/declared on the scope instead and have it take the data it uses as a parameter.
// initialize it so your code does not blow up in the case of forgotten undefined or null check
$scope.nameList = [];
$scope.loadRuleList = function() {
var me = this;
PrioritizeService.getData($scope.MyURL).
then(function(response) {
if (response) {
Types = response;
}
// re-init the nameList field
me.nameList = [];
for (var k = 0; k < Types.length; k++) {
me.nameList.push(Types[k].name)
}
//check for duplicates
var areDups = me.checkDupsName(me.nameList);
}
}
$scope.checkDupsName = function(listToCheck) {
var i, j, n;
n = listToCheck.length;
for (i = 0; i < n; i++) {
for (j = i + 1; j < n; j++) {
if (listToCheck[i] === listToCheck[j]) {
return true;
}
}
}
return false;
}

What's wrong in my JS function?

I am optimizing a Java code to JS, but runs on Nashorn and do not own debug option. The input is val = "JPG ou PNG" and the output is "JPG ou PNG". Why does this happen? I need the output to be "jpg/png"
Function
function process(val) {
var cleaned = val.replaceAll("[•×\\tª°▪º⊗ fi ²●˚~ĩ`ũ]", "").trim().toLowerCase();
var out = [];
if (cleaned.contains("ou")) {
out = cleaned.split("ou");
}
else if (cleaned.contains("/")) {
out = cleaned.split("/");
}
else {
return cleaned;
}
for (var i = 0; i < out.length; i++) {
out[i] = out[i].trim();
}
return join(out, "/");
}
Three of your functions don't exist in javascript:
replaceAll(searchValue, newValue) in javascript is replace(searchValue, newValue)
contains(searchValue) in javascript is indexOf(searchValue) > -1
join(array, separator) in javascript is array.join(separator)
JSFIDDLE DEMO
Here's my solution:
function process(val) {
var cleaned = val.replace("[•×\\tª°▪º⊗ fi ²●˚~ĩ`ũ]", "").trim().toLowerCase();
var out = [];
if (cleaned.indexOf("ou") >= 0) {
out = cleaned.split("ou");
}
else if (cleaned.indexOf("/") >= 0) {
out = cleaned.split("/");
}
else {
return cleaned;
}
for (var i = 0; i < out.length; i++) {
out[i] = out[i].trim();
}
return join(out, "/");
}
Your logic was right, but strings in Javascript don't have 'replaceAll' and 'contains', so I replaced them with 'replace' and 'indexOf(x) >= 0'.
Also, you mentioned you don't have the option to debug in your environment, yet the function you provided is pretty standalone. This means you could easily copy it into another environment to test it in isolation.
For example, I was able to wrap this code in a HTML file then open it in my web browser (I had to implement my own 'join').
<html>
<body>
<script>
function join(val, divider) {
var out = "";
for(var i = 0; i < val.length; i++) {
if(out.length > 0) out += divider;
out += val[i];
}
return out;
}
function process(val) {
var cleaned = val.replace("[•×\\tª°▪º⊗ fi ²●˚~ĩ`ũ]", "").trim().toLowerCase();
var out = [];
if (cleaned.indexOf("ou") >= 0) {
out = cleaned.split("ou");
}
else if (cleaned.indexOf("/") >= 0) {
out = cleaned.split("/");
}
else {
return cleaned;
}
for (var i = 0; i < out.length; i++) {
out[i] = out[i].trim();
}
return join(out, "/");
}
var inval = "JPG ou PNG";
var outval = process(inval);
console.log(inval + " => " + outval);
</script>
</body>
</html>
I verified it works by opening up the console and seeing the output "JPG ou PNG => jpg/png".

Is there a single function to check an array contains another array?

[1,2,3].CONTAINS([1,2]) ==> true
[1,2,3].CONTAINS([1,2,3,4]) ==> false
or
{a:1,b:2,c:3}.HASKEYS([a,b]) ==> true
{a:1,b:2,c:3}.HASKEYS([a,b,c,d]) ==> false
Is there a single function to check an array contains another array?
No, but you can make one:
Array.prototype.contains = function(other) {
for (var i = 0; i < other.length; i++) {
if (this.indexOf(other[i]) === -1) return false;
}
return true;
}
And if order matters:
Array.prototype.contains = function(other) {
var broken;
if (!other.length) return true;
for (var i = 0; i < this.length - other.length + 1; i++) {
broken = false;
for (var j = 0; j < other.length; j++) {
if (this[i + j] !== other[j]) {
broken = true;
break;
}
}
if (!broken) return true;
}
return false;
}
The other function is similar, so I'll leave it to you to finish:
Object.prototype.has_keys = function(keys) {
...
}

Categories

Resources