Angular JS break ForEach

256

Tengo un bucle foreach angular y quiero romper el bucle si coincido con un valor. El siguiente código no funciona.

angular.forEach([0,1,2], function(count){
  if(count == 1){
    break;
  }
});

Cómo puedo conseguir esto?

Gordito chico
fuente
1
No entiendo por qué no solo encuentras el valor en lugar de entrar en un bucle. Tal vez el ejemplo que diste no cuenta toda la historia, pero prefiero hacer lo que @Aman dijo a continuación. ¿Por qué entrar en el ciclo como se menciona a continuación y realizar una verificación cada vez que some () hace exactamente eso de una manera más elegante? Recuerde que si trata javascript como un lenguaje funcional, no debería tener sentido usar estos tipos de estructuras de control para / while / break. Es por eso que existe foreach, find, some, etc.
Adrián Rodríguez

Respuestas:

264

No hay forma de hacer esto. Ver https://github.com/angular/angular.js/issues/263 . Dependiendo de lo que esté haciendo, puede usar un booleano para no entrar en el cuerpo del bucle. Algo como:

var keepGoing = true;
angular.forEach([0,1,2], function(count){
  if(keepGoing) {
    if(count == 1){
      keepGoing = false;
    }
  }
});
dnc253
fuente
45
Prefiero simplemente agregar un !keepGoing && return;a la parte superior de la función, menos código.
Andrew Joslin
46
Estas no son las mejores prácticas, aquí angular para cada bucle nunca se rompe, Y no hay nada que rompa angular.para cada uno. Native for loop es un 90% más rápido que angular.forEach. Por lo tanto, es mejor usar el bucle nativo para cuando desee romper la coincidencia de condición. Gracias
Nishchit Dhanani
xcatly donde me quedé ... y esto ayudó ... gracias una tonelada ... De todos modos, me gustaría saber la razón para hacer que cada bucle sea irrompible. Si alguno
Saurabh Tiwari
Esta no debería ser la respuesta aceptada, ya que no rompe el ciclo forEach. Es una forma de no ejecutar toda la lógica dentro del bucle.
Nebulosar
296

El angular.forEachbucle no puede romperse en una coincidencia de condición.

Mi consejo personal es usar un bucle NATIVE FOR en lugar de angular.forEach.

El bucle NATIVE FOR es aproximadamente un 90% más rápido que otro para los bucles.

Para salto de bucle, para resultado de prueba de bucle

USO PARA lazo en ANGULAR:

var numbers = [0, 1, 2, 3, 4, 5];

for (var i = 0, len = numbers.length; i < len; i++) {
  if (numbers[i] === 1) {
    console.log('Loop is going to break.'); 
    break;
  }
  console.log('Loop will continue.');
}
Nishchit Dhanani
fuente
1
Esto no funciona para mi. Todo lo que hace es terminar esta iteración particular del bucle. Pero luego pasa a la siguiente iteración.
Ben
1
@Ben, lo siento ben, fue mi error, pero ahora actualizo mi respuesta después de una larga investigación. Espero que esto ayude . Gracias
Nishchit Dhanani
1
@LGama: - ¿Cuál es tu caso?
Nishchit Dhanani
3
jsperf.com/angular-foreach-performance pruébelo en su propio navegador para decidir qué función debe elegir. He probado en IE11 y también es tan rápido como en la captura de pantalla. También probé Array.some () pero es más lento que Array.forEach () en IE11 pero podría ser más rápido que angular.foreach ;-). O pruébelo aquí jsperf.com/angular-foreach-vs-native (todos los créditos van al autor original, no a mí ;-))
Sebastian
66
Incluso con jsperf no se puede decir "nativo porque es aproximadamente 90% más rápido". En su escenario, esto depende en gran medida de lo costosa que sea la ejecución de la función interna y cuántas ejecuciones se pueden guardar al salir del bucle (interrupción) temprano.
hgoebl
22

utilice algunas o todas las instancias de ForEach,

Array.prototype.some:
some is much the same as forEach but it break when the callback returns true

Array.prototype.every:
every is almost identical to some except it's expecting false to break the loop.

Ejemplo para algunos:

var ary = ["JavaScript", "Java", "CoffeeScript", "TypeScript"];

ary.some(function (value, index, _ary) {
    console.log(index + ": " + value);
    return value === "JavaScript";
});

Ejemplo para cada:

var ary = ["JavaScript", "Java", "CoffeeScript", "TypeScript"];

ary.every(function(value, index, _ary) {
    console.log(index + ": " + value);
    return value.indexOf("Script") > -1;
});

Encuentre más información
http://www.jsnoob.com/2013/11/26/how-to-break-the-foreach/

Neo Vijay
fuente
no @ AngelS.Moreno, todos prefieren usar una variable local en lugar de un método diseñado específicamente para el caso en cuestión
Oded Niv
18

Utilice la matriz algún método

 var exists = [0,1,2].some(function(count){
      return count == 1
 });

Existe devolverá verdadero, y puede usar esto como una variable en su función

if(exists){
    console.log('this is true!')
}

Arreglar algún método - Javascript

Aman Fahimullah
fuente
44
Para mí, la única razón para usar angular.forEach()es que tengo que soportar IE8, que no tiene Array.forEach()... o Array.some().
Bennett McElwee
2
Puede polyfill Array.forEach fácilmente. Vea la parte inferior de la página: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
zumalifeguard
6

Hasta donde yo sé, Angular no proporciona esa función. Es posible que desee utilizar la find()función de subrayado para esto (es básicamente un forEach que se sale del bucle una vez que la función devuelve verdadero).

http://underscorejs.org/#find

mna
fuente
Esto puede resolver el problema lateralmente, pero no rompe el bucle.
Elise Chant
O nativo para loop
shanti
6

Si usa jQuery (por lo tanto, no jqLite) junto con AngularJS, puede iterar con $ .each, lo que permite dividir y continuar según la expresión de valor de retorno booleano.

JSFiddle:

http://jsfiddle.net/JEcD2/1/

Javascript:

var array = ['foo', 'bar', 'yay'];
$.each(array, function(index, element){
    if (element === 'foo') {
        return true; // continue
    }
    console.log(this);
    if (element === 'bar') {
        return false; // break
    }
});

Nota:

Aunque el uso de jQuery no es malo, MDN recomienda tanto las funciones nativas Array.some como Array.Cada una de las siguientes :

"No hay forma de detener o romper un ciclo forEach. La solución es usar Array.every o Array.some"

MDN proporciona los siguientes ejemplos:

Array.some:

function isBigEnough(element, index, array){
    return (element >= 10);
}
var passed = [2, 5, 8, 1, 4].some(isBigEnough);
// passed is false
passed = [12, 5, 8, 1, 4].some(isBigEnough);
// passed is true

Array.every:

function isBigEnough(element, index, array){
    return (element >= 10);
}
var passed = [12, 5, 8, 130, 44].every(isBigEnough);
// passed is false
passed = [12, 54, 18, 130, 44].every(isBigEnough);
// passed is true
conceptdeluxe
fuente
6

Concretamente, puede salir de un forEachbucle, y de cualquier lugar, lanzar una excepción.

try {
   angular.forEach([1,2,3], function(num) {
      if (num === 2) throw Error();
   });
} catch(e) {
    // anything
}

Sin embargo, es mejor si usa otra biblioteca o implementa su propia función, una findfunción en este caso, por lo que su código es de alto nivel.

Victor Aguilar
fuente
10
Bueno, ¡respondiste la pregunta! Aunque espero que nadie haga eso :)
Jason Cox
Lanzar una excepción innecesariamente no es una buena forma de manejar la situación. En su lugar, verifique la solución proporcionada por @ dnc253 stackoverflow.com/a/13844508/698127
Aamol
4

Intenta esto como descanso;

angular.forEach([0,1,2], function(count){
  if(count == 1){
    return true;
  }
});
panatoni
fuente
3

Como dicen las otras respuestas, Angular no proporciona esta funcionalidad. Sin embargo, jQuery sí lo hace, y si ha cargado jQuery y Angular, puede usar

jQuery.each ( array, function ( index, value) {
    if(condition) return false; // this will cause a break in the iteration
})

Ver http://api.jquery.com/jquery.each/

Nik Dow
fuente
2
El OP solicitó una solución AngularJS, la respuesta correcta es NO :)
Shannon Hochkins
3

Normalmente no hay forma de romper un "cada" bucle en javascript. Lo que se puede hacer generalmente es usar el método de "cortocircuito".

    array.forEach(function(item) {
      // if the condition is not met, move on to the next round of iteration.
      if (!condition) return;

      // if the condition is met, do your logic here
      console.log('do stuff.')
    }

Downhillski
fuente
2

break no es posible lograrlo en angular para cada uno, necesitamos modificar for cada para hacer eso.

$scope.myuser = [{name: "Ravi"}, {name: "Bhushan"}, {name: "Thakur"}];  
                angular.forEach($scope.myuser, function(name){
                  if(name == "Bhushan") {
                    alert(name);
                    return forEach.break(); 
                    //break() is a function that returns an immutable object,e.g. an empty string
                  }
                });
rb4bhushan
fuente
Esta respuesta no parece completa. Indique si break()es necesario definirlo o si ya forma parte de angular. Por favor defina si no.
geodésico
2

Puedes usar esto:

var count = 0;
var arr = [0,1,2];
for(var i in arr){
   if(count == 1) break;
   //console.log(arr[i]);
}
endrcn
fuente
1
var ary = ["JavaScript", "Java", "CoffeeScript", "TypeScript"];
var keepGoing = true;
ary.forEach(function(value, index, _ary) {
    console.log(index)
    keepGoing = true;
    ary.forEach(function(value, index, _ary) {
        if(keepGoing){ 
            if(index==2){
                keepGoing=false;
            }
            else{
                console.log(value)
            }

        }      
    });
});
usuario1693371
fuente
0
$scope.arr = [0, 1, 2];  
$scope.dict = {}
for ( var i=0; i < $scope.arr.length; i++ ) {
    if ( $scope.arr[i] == 1 ) {
        $scope.exists = 'yes, 1 exists';
        break;
    }
 }
 if ( $scope.exists ) {
     angular.forEach ( $scope.arr, function ( value, index ) {
                      $scope.dict[index] = value;
     });
 }
solanki ...
fuente
0

Preferiría hacer esto a cambio. Coloque la parte de bucle en la función privada y regrese cuando desee romper el bucle.

PrabaharanKathiresan
fuente
0

Me doy cuenta de que esto es antiguo, pero un filtro de matriz puede hacer lo que necesita:

var arr = [0, 1, 2].filter(function (count) {
    return count < 1;
});

Luego puede ejecutar arr.forEachy otras funciones de matriz.

Me doy cuenta de que si tiene la intención de reducir por completo las operaciones de bucle, esto probablemente no hará lo que desea. Para eso mejor uso while.

Orilla
fuente
0

Este ejemplo funciona. Intentalo.

var array = [0,1,2];
for( var i = 0, ii = array.length; i < ii; i++){
  if(i === 1){
   break;
  }
}
Maikel Rosabal
fuente
1
Supongo que no quiere un for bucle, su caso de uso necesita un foreachno forprobablemente
Hassen Ch.
0

Use Retorno para romper el ciclo.

angular.forEach([0,1,2], function(count){
  if(count == 1) {
    return;
  }
});
Shanmugarajan
fuente
0
onSelectionChanged(event) {
    let selectdata = event['api']['immutableService']['gridOptionsWrapper']['gridOptions']['rowData'];
    let selected_flag = 0;

    selectdata.forEach(data => {
      if (data.selected == true) {
        selected_flag = 1;
      }
    });

    if (selected_flag == 1) {
      this.showForms = true;
    } else {
      this.showForms = false;
    }
}
poovarasi sekar
fuente
-1

Yo usaría en returnlugar de break.

angular.forEach([0,1,2], function(count){
  if(count == 1){
    return;
  }
});

Funciona de maravilla.

Aakash
fuente
Esta no es una solución válida. look: prueba de función () {angular.forEach ([1,2,3,4,5,6,7,8,9], function (value, index) {if (value == 2) return; console.log (valor);})} salida:> teste (); 1 3 4 5 6 7 8 9
otaviodecampos
-2

Simplemente agregue $ index y haga lo siguiente:

angular.forEach([0,1,2], function(count, $index) {
     if($index !== 1) {
          // do stuff
     }
}
Sultán
fuente
OP quiere salir del ciclo.
Angel S. Moreno