JavaScript each in grep function - javascript

I have problem using grep function. My code is
var zapis = jQuery.grep(ListaGrupa, function(v, k) {
console.log($(that).attr("kursid"));
if (v.grupa.ID == $(that).attr("kursid")) {
idZaBrisanje = v.kategorija.Id;
return true;
}
if ($.each(v.grupa.Podgrupe, function(kljuc, vrednost) {
if (vrednost.podgrupa.ID == $(that).attr("kursid")) {
idZaBrisanje = vrednost.podkategorija.Id;
return true;
}
}))
return false;
})[0];
But is seems return true is in each scope, so in wont affect on grep function, so I get empty results.
Any help?

Yes, the return true in this case will act instruct your each function to continue the iteration. It will not break out of your grep function.
Instead, you may want to set a flag, and then return false, so as to terminate the iteration:
var found = false;
$.each(function() {
if(condition) {
found = true;
return false;
}
});
if(found)
return true;
Furthermore, $.each will always return the iterated object, which will always be truthy, so you can't use that inside a condition the way you're doing.
This is a scenario where you may reconsider whether jQuery is actually helping you. You may consider falling back to a regular for loop here, which would allow you to return out of the grep function immediately from within the iteration.
for(var i = 0; l = v.grupa.Podgrupe; i<l; i++) {
var vrednost = v.grupa.Podgrupe[i];
if(condition)
return true;
}

Related

Difference between JQuery $.each loop and JS for loop [duplicate]

I want to return false and return from function if I find first blank textbox
function validate(){
$('input[type=text]').each(function(){
if($(this).val() == "")
return false;
});
}
and above code is not working for me :(
can anybody help?
You are jumping out, but from the inner loop, I would instead use a selector for your specific "no value" check, like this:
function validate(){
if($('input[type=text][value=""]').length) return false;
}
Or, set the result as you go inside the loop, and return that result from the outer loop:
function validate() {
var valid = true;
$('input[type=text]').each(function(){
if($(this).val() == "") //or a more complex check here
return valid = false;
});
return valid;
}
You can do it like this:
function validate(){
var rv = true;
$('input[type=text]').each(function(){
if($(this).val() == "") {
rv = false; // Set flag
return false; // Stop iterating
}
});
return rv;
}
That assumes you want to return true if you don't find it.
You may find that this is one of those sitautions where you don't want to use each at all:
function validate(){
var inputs = $('input[type=text]');
var index;
while (index = inputs.length - 1; index >= 0; --index) {
if (inputs[index].value == "") { // Or $(inputs[index]).val() == "" if you prefer
return false;
}
}
// (Presumably return something here, though you weren't in your example)
}
I want to add something to existing answers to clear the behavior of $(selector).each and why it doesn't respect return false in OP's code.
return keyword inside $(selector).each is used to break or continue the loop. If you use return false, it is equivalent to a break statement inside a for/while loop. Returning non-false is the same as a continue statement in a for loop; it will skip immediately to the next iteration. Source
Because you're returning false, the loop breaks and the function ends up returning undefined in your case.
Your option is to use a var outside $.each or avoid using it altogether as #TJCrowder wrote.

The return false in jquery each loop not end the entire function

It seems that the return word in jquery each loop will not end the entire function. Here is the code below. The purpose is, when a value in the array is not a number, it should stop all the function, not only the loop. But it turns out that it will only stop the loop and contiue the other logic below.
In C# or Java, the return word will stop the entire function. Is not desgined like this in JavaScript?
function testMehtod() {
var itemIds = [];
$("#confirmOrderItemContainer").find(":checkbox:checked").each(function (i, o) {
itemIds[i] = $(o).attr('item-id');
if (isNaN(itemIds[i])) {
return false;
}
});
//other logic ...
}
if you need to catch breaking the loop and return false too:
function testMehtod() {
var itemIds = [];
var ret = true; // our flag variable with default value - everything is good
$("#confirmOrderItemContainer").find(":checkbox:checked").each(function (i, o) {
itemIds[i] = $(o).attr('item-id');
if (isNaN(itemIds[i])) { // not good
ret = false; // let set flag about it
return false; // break $.each loop
}
});
if (ret === false) { // not good? let's leave function
return false;
}
//other logic ...
}

how to itereate an json object in angularjs using for loop?

I have one array i want to iterate that in the iteration process we check one condition if condition is true we return one value otherwise we return else part I write some code but its not working.
the loop will not terminated if condition is true how can i do that cam anyone help me?
$scope.bgImages = []; //it having some objects
$scope.job = []; //it also having some objeccts
//if both elements are matching we return one value
$scope.getJobDepartmentImg = function() {
var jobDepartment = $scope.job.department;
for (var i in $scope.bgImages) {
var department = $scope.bgImages[i].departmentName;
var job_header = $scope.bgImages[i].s3ImageUrl;
if (jobDepartment === department) {
return job_header;
} else {
return default_job_header;
}
}
};
The loop is not terminated if condition is satisfiedd that method will continiouslyy can anyone help me?
put an second return outside else statement
$scope.getJobDepartmentImg = function() {
var jobDepartment = $scope.job.department;
for (var i in $scope.bgImages) {
var department = $scope.bgImages[i].departmentName;
var job_header = $scope.bgImages[i].s3ImageUrl;
if(jobDepartment === department){
return job_header;
}
}
return default_job_header;
}
it will iterate through array and return job_header if it finds one, or return default if loop ends

Get object out of observable array

Why is m "undefined" in this code:
currentViewModel = ko.mapping.fromJS(viewModel);
currentViewModel.getReport = function(reportId) {
for(var i=0;i<currentViewModel.availableReports().length;i++) {
if(currentViewModel.availableReports()[i].id == reportId) {
var m = currentViewModel.availableReports()[i];
return currentViewModel.availableReports()[i];
}
}
}
I call getReport() as an onclick event and I want to send the report object to a view (modal) I can do a foreach on the availableReports and it's all there. When I run through the debugger, it loops through the array and finds the right one. But why can't I pull it out of the array? "m" remains undefined the the function returns undefined.
What am I missing here?
EDIT: there is a follow up question here:
Can knockout.js wait to bind until an onClick?
You just need to change if(currentViewModel.availableReports()[i].id ... to if(currentViewModel.availableReports()[i].id() ... because after mapping id will become an observable, i.e. function.
Updated code:
currentViewModel = ko.mapping.fromJS(viewModel);
currentViewModel.getReport = function(reportId) {
for (var i = 0; i < currentViewModel.availableReports().length; i++) {
if (currentViewModel.availableReports()[i].id() == reportId) {
var m = currentViewModel.availableReports()[i];
return currentViewModel.availableReports()[i];
}
}
}
Demo - Fiddle.
I'll repeat the solution from #NikolayErmakov's answer here, but want to add two things to get a more complete answer. You end with:
...m remains undefined and the function returns undefined.
What am I missing here?
You're missing two things:
The var m bit of the first statement inside the if is hoisted to the top of the current scope (the top of the function). This is why the debugger can tell you what m is, even if you never reach the line of code it's on.
If a function invocation reaches the end of a function (as is the case for you, since you never go inside the if) without seeing an explicit return statement, it will return undefined.
To better understand this, you should interpret your function like this:
currentViewModel.getReport = function(reportId) {
var m;
for (var i = 0; i < currentViewModel.availableReports().length; i++) {
if (currentViewModel.availableReports()[i].id == reportId) {
m = currentViewModel.availableReports()[i];
return currentViewModel.availableReports()[i];
}
}
return undefined;
}
Some people (e.g. Douglas Crockford) do recommend placing var statements at the top of a function, though it's a matter of style to some degree. I don't think many people explicitly return undefined at the end of a function, though in your case I might be explicit about that scenario and return null (or throw an Error even).
As promised, I'll repeat the actual solution, as I concur with the other answer:
you need to invoke id as a function to get its value (because the mapping plugin will map to observable()s.
In addition:
I'd retrieve the array only once
I'd suggest using === instead of ==
Here's my v0.5 version:
currentViewModel.getReport = function(reportId) {
var m = null, reports = currentViewModel.availableReports();
for (var i = 0; i < reports.length; i++) {
if (reports[i].id() === reportId) {
m = reports[i];
return m;
}
}
return m;
}
But I'd optimize it to this v1.0:
currentViewModel.getReport = function(reportId) {
var reports = currentViewModel.availableReports();
for (var i = 0; i < reports.length; i++) {
if (reports[i].id() === reportId) {
return reports[i];
}
}
return null;
}
For completeness, here's another version that utilizes filter on arrays:
currentViewModel.getReport = function(reportId) {
var reports = currentViewModel.availableReports().filter(function(r) { return r.id() === reportId; });
return reports.length >= 1 ? reports[0] : null;
}

Working equivalent for method .some() in javascript or jquery?

Was looking for "equivalent for some method in javascript" and "return just one value if is in array", but saw only the answers to the way in which to determine the type of variables or too many unnecessary.
I bypass all inputs in html and i want something like this:
$('#goodsFilter')
.find('input[type="number"]')
.some(function(i,el){
return (isNumber($(el).val())) ? 1 : 0;
});
But it throws an error:
"TypeError: 'undefined' is not a function" (eg. Safari 6.0.4).
UPD: Error comes from the last line, yeah, where });.
isNumber:
function isNumber(n) { return !isNaN(parseFloat(n)) && isFinite(n); }
This should check for the presence of each input information, and, if at least one of them is not empty, return 1, otherwise 0.
How can I replace it to work in most modern browsers?
UPD:
Problem was solved. I'm a little confused in choosing the answer. The code of #RobG implementation of .some() is more understandable for beginners (and I am) so I switched my vote.
For anyone else who comes to this thread, you can use some() on a jQuery object this way:
$.makeArray($(...)).some(function(x) { ... })
jQuery.makeArray() converts the jQuery object into an Array, so you can use some() on it.
As suggested by #alf-eaton, you could use:
$(…).toArray().some(function(node) { … })
Array.prototype.some returns true or false, so you can do:
.some(function(el){
return !isNaN(el.value);
}
You don't say where the error comes from, is it from the call to isNumber?
Edit
Ah, so your issue is with some.
If you want a jQuery some method, then it should at least mimic the built–in ECMAScript some, which takes two arguments: a callback function and an optional this argument.
The callback function should take three arguments: the value, the index (optional) and an optional value to use as the this argument. It should access the numeric members in ascending order and only visit members that actually exist.
So it should be something like (noting that jQuery.fn === jQuery.prototype):
jQuery.fn.some = function(fn, thisArg) {
var result;
for (var i=0, iLen = this.length; i<iLen; i++) {
if (this.hasOwnProperty(i)) {
if (typeof thisArg == 'undefined') {
result = fn(this[i], i, this);
} else {
result = fn.call(thisArg, this[i], i, this);
}
if (result) return true;
}
}
return false;
}
So if you want now you can do:
var result = $('#goodsFilter')
.find('input[type="number"]')
.some(function(el) {
return isNumber(el.value);
})? 1 : 0;
or you can do either of the following to coerce true to 1 and false to 0:
var result = Number($('#goodsFilter')
.find('input[type="number"]')
.some(function(el) {
return isNumber(el.value);
}));
or
var result = +($('#goodsFilter')
.find('input[type="number"]')
.some(function(el) {
return isNumber(el.value);
}));
The above is only lightly tested, the optional thisArg parameter might be redundant.
You could use the .filter method, and then check the length.
$('#goodsFilter')
.find('input[type="number"]')
.filter(function(i,el){ return isNumber($(el).val())); })
.length > 0
$(...).is(function) should work too. The jQuery API documentation states (emphasis mine):
Check the current matched set of elements against a selector, element, or jQuery object and return true if at least one of these elements matches the given arguments.
So using the example in the question, we would have something like:
var result = $('#goodsFilter')
.find('input[type="number"]')
.is(function(idx, el) {
return isNumber(el.value);
})? 1 : 0;
. . In the most basic version, you can just create a "some" function:
function eSome(arr, f) { var i = 0, n = arr.length;
for (;i<n;i++) { if (!i in arr) { continue }
if (f(i, arr[i])) { return true; }
} return false;
}
var list = [0, 1, 2, 3, 4, 5];
var testFunction = function (i, e) { return e === 2; };
console.log(eSome(list, testFunction));
//returns true and the loop ran only for the necessary three times.
. . If you want to chain the .some call in a jQuery object, you can add it as a jQuery function as well, using something like this (now tested and fixed) example:
jQuery.fn.some = function (f) { var i = 0, n = this.length;
for (;i<n;i++) { if (!i in this) { continue }
if (f(i, this[i])) { return true; }
}
return false;
}
$('.a').some(function (i, el) { return ($(el).text() == 'weeee!'); });
. . As #RobG pointed out in the comments, the native Array.prototype.some implementation calls your callback with a different set of parameters. I'm following the OP's sample code, but you can mimic the ECMA implementation's parameter with if (f(this[i], i, this)) { return true; } inside the loop.
. . You can also shim it on Array.prototype.some, but I strongly advise against any direct modifications to the built-in prototypes.
Implementation in Vanilla Javascript( with arrow syntax)
function some(arr,callback){
for(let i=0;i<arr.length;i++){
if(callback(arr[i],i,arr)){
return true;
}
}
return false;
}
some use:
check if an array has an even number:
function hasEvenNum(arr){
return arr.some(value=>{
return value % 2 === 0;
});
}
Try to use [].prototype.call method, the first argument will be an Array-like value, the second one is a function that will be called on each element.
[].some.call($('#goodsFilter').find('input[type="number"]'), function (el) {
return isNumber($(el).val());
});

Categories

Resources