Obtenga un objeto específico por id de una matriz de objetos en AngularJS

111

Tengo un archivo JSON que contiene algunos datos a los que me gustaría acceder en mi sitio web AngularJS. Ahora lo que quiero es obtener solo un objeto de la matriz. Así que me gustaría, por ejemplo, el artículo con id 1.

Los datos se ven así:

{ "results": [
    {
        "id": 1,
        "name": "Test"
    },
    {
        "id": 2,
        "name": "Beispiel"
    },
    {
        "id": 3,
        "name": "Sample"
    }
] }

Me gustaría cargar los datos con la funcionalidad AngularJS $ http como esta:

$http.get("data/SampleData.json");

que está funcionando. Pero, ¿cómo puedo obtener un objeto de datos específico (por id) de la matriz de la que obtengo $http.get?

Gracias de antemano por tu ayuda.

Saluda a Marc

mooonli
fuente
¿Lo has intentado tú mismo? Si es así, ¿podemos ver lo que se te ocurrió?
simonlchilds
1
Bueno, no tengo idea de qué forma sería la mejor usando AngularJS. Lo que no me gusta es iterar sobre la matriz y hacer un igual en la identificación. ¿Quizás haya una mejor manera?
mooonli
Debe confiar en underscorejs o bibliotecas similares para dicho procesamiento. AngularJS es un marco MVVM y es posible que no tenga una API para esto.
Vijay Pande
@marcbaur - tienes que iterar la matriz. Incluso si usa guión bajo, o algo similar, sus funciones, detrás de escena, simplemente están iterando.
Adam
1
por favor agregue código angular para esto
Ankush Kondhalkar

Respuestas:

4

La única forma de hacer esto es iterar sobre la matriz. Obviamente, si está seguro de que los resultados están ordenados por id, puede hacer una búsqueda binaria

Antonio E.
fuente
46
... Realmente espero que después de leer esta respuesta, la gente no crea que es una buena idea ordenar una matriz y luego hacer una búsqueda binaria. La búsqueda binaria es inteligente , claro, pero solo si la matriz ya está ordenada, y en realidad es: 1. fácil de implementar mal, 2. Más difícil de leer si está mal implementada.
Ben Lesh
4
Agradecería mucho que los votantes en contra pudieran motivar su decisión.
Antonio E.
1
Por defecto, el tipo de matriz de JavaScript tiene el método find (). El método find () devuelve el valor del primer elemento de la matriz que satisface la función de prueba proporcionada.
abosancic
246

Usando la solución ES6

Para aquellos que aún leen esta respuesta, si está utilizando ES6, el findmétodo se agregó en matrices. Entonces, asumiendo la misma colección, la solución sería:

const foo = { "results": [
    {
        "id": 12,
        "name": "Test"
    },
    {
        "id": 2,
        "name": "Beispiel"
    },
    {
        "id": 3,
        "name": "Sample"
    }
] };
foo.results.find(item => item.id === 2)

Yo optaría totalmente por esta solución ahora, ya que está menos vinculado a angular o cualquier otro marco. Javascript puro.

Solución angular (solución anterior)

Apunté a resolver este problema haciendo lo siguiente:

$filter('filter')(foo.results, {id: 1})[0];

Un ejemplo de caso de uso:

app.controller('FooCtrl', ['$filter', function($filter) {
    var foo = { "results": [
        {
            "id": 12,
            "name": "Test"
        },
        {
            "id": 2,
            "name": "Beispiel"
        },
        {
            "id": 3,
            "name": "Sample"
        }
    ] };

    // We filter the array by id, the result is an array
    // so we select the element 0

    single_object = $filter('filter')(foo.results, function (d) {return d.id === 2;})[0];

    // If you want to see the result, just check the log
    console.log(single_object);
}]);

Plunker: http://plnkr.co/edit/5E7FYqNNqDuqFBlyDqRh?p=preview

Willemoes
fuente
1
De hecho, creo que sí. Después de obtener la matriz, puede usar la función $ filter para filtrar el elemento con la identificación correcta.
flup
10
Esta debería ser la respuesta aceptada. Tenía la misma pregunta en mi cabeza y esta respuesta es la única que usa AngularJS existente y no está reinventando la rueda. Y sí, está funcionando.
Zoran P.
4
+1 por ser esta la respuesta aceptada. La mejor solución usando bibliotecas angulares.
Meki
1
Plunker con filtro en una expresión: plnkr.co/edit/yc0uZejGqWTcUVKvI7Tq?p=preview
Aaron Roller
4
Tenga en cuenta que los filtros encuentran por defecto subcadenas que no distinguen entre mayúsculas y minúsculas. Entonces (foo.results, {id: 2}) devuelve [{id: 12}, {id: 2}], {id: 222}] pero (foo.results, function (d) {return d.id == = 2;}) devuelve [{id: 2}]
Ryan.lay
26

Para cualquiera que esté mirando esta publicación anterior, esta es la forma más fácil de hacerlo actualmente. Solo requiere un AngularJS $filter. Es como la respuesta de Willemoes, pero más breve y más fácil de entender.

{ 
    "results": [
        {
            "id": 1,
            "name": "Test"
        },
        {
            "id": 2,
            "name": "Beispiel"
        },
        {
            "id": 3,
            "name": "Sample"
        }
    ] 
}

var object_by_id = $filter('filter')(foo.results, {id: 2 })[0];
// Returns { id: 2, name: "Beispiel" }

ADVERTENCIA

Como dice @mpgn, esto no funciona correctamente . Esto obtendrá más resultados. Ejemplo: cuando busca 3, esto también capturará 23

Tillman32
fuente
1
también captura de identificación: 24 12 222 2002 etc
mpgn
Creo que eso [0]haría que devolviera el primer resultado que encuentra de la colección, por lo que solo funcionaría si su colección está ordenada y el objeto que está buscando es el primero que encuentra durante su iteración. P.ej. si hay un id: 12 que viene antes del id: 2, devolvería id: 12.
Roddy of the Frozen Peas
25

personalmente utilizo guión bajo para este tipo de cosas ...

a = _.find(results,function(rw){ return rw.id == 2 });

entonces "a" sería la fila que deseaba de su matriz donde la identificación era igual a 2

Jason Boerner
fuente
1
Realmente me encanta el subrayado, pero, ¿es peor tener otra biblioteca de JavaScript?
Genuinefafa
8
Tenga en cuenta que findpotencialmente puede devolver varios objetos. Como solo queremos uno, podemos usar el findWhereque solo devuelve la primera aparición (que sabemos que es la única aparición), por ejemplo a = _.findWhere(results, {id: 2}).
gregoltsov
16

Solo quiero agregar algo a la respuesta de Willemoes . El mismo código escrito directamente dentro del HTML se verá así:

{{(FooController.results | filter : {id: 1})[0].name }}

Suponiendo que "resultados" es una variable de su FooController y desea mostrar la propiedad "nombre" del elemento filtrado.

Ena
fuente
@ Ena-¿Cómo verificar que el resultado del filtro no sea nulo o indefinido?
Abhijeet
Usé esta variante de HTML porque estaba seguro de que existía un resultado. Lo intenté y si no hay resultado la consola no da ningún error, simplemente deja el texto en blanco. Si necesita hacer algo de lógica si no se encuentra ningún resultado, creo que la mejor manera de hacerlo es la respuesta de Willemoes (código js dentro del controlador). En ese ejemplo, debe verificar en HTML si la variable single_object es nula o no está definida.
Ena
2
{{(FooController.results | filter: {id: 1}) [0] .name}: true} - si alguien está buscando una coincidencia exacta
George Sharvadze
12

Puede usar ng-repeaty seleccionar datos solo si los datos coinciden con lo que está buscando usando, ng-show por ejemplo:

 <div ng-repeat="data in res.results" ng-show="data.id==1">
     {{data.name}}
 </div>    
James Kuta Simiyu
fuente
2
Si su matriz tiene más de un número trivial de elementos, esto creará una gran cantidad de ámbitos innecesarios que pueden ralentizar su aplicación.
The DIMM Reaper
9

Puede simplemente recorrer su matriz:

var doc = { /* your json */ };

function getById(arr, id) {
    for (var d = 0, len = arr.length; d < len; d += 1) {
        if (arr[d].id === id) {
            return arr[d];
        }
    }
}

var doc_id_2 = getById(doc.results, 2);

Si no desea escribir estos bucles desordenados, puede considerar usar underscore.js o Lo-Dash (ejemplo en este último):

var doc_id_2 = _.filter(doc.results, {id: 2})[0]
Kamituel
fuente
8

Si desea la lista de elementos como ciudad sobre la base de la identificación del estado, use

var state_Id = 5;
var items = ($filter('filter')(citylist, {stateId: state_Id }));
Ali Adravi
fuente
7

Desafortunadamente (a menos que me equivoque), creo que debe iterar sobre el objeto de resultados.

for(var i = 0; i < results.length; i += 1){
    var result = results[i];
    if(result.id === id){
        return result;
    }
}

Al menos de esta manera, saldrá de la iteración tan pronto como encuentre la identificación correcta.

Simonlchilds
fuente
¿Por qué? ¿Tienes algo que respalde eso?
simonlchilds
11
Bueno, ¿sabes qué ...? Me fui a releer Javascript - ¡las partes buenas para contrarrestar tu argumento y estoy equivocado! ¡Durante todo este tiempo lo he estado haciendo mal! Sin embargo, no me ha causado ningún problema ... todavía. Actualicé mi respuesta.
simonlchilds
6

¿Por qué complicar la situación? esto es simple escribir alguna función como esta:

function findBySpecField(data, reqField, value, resField) {
    var container = data;
    for (var i = 0; i < container.length; i++) {
        if (container[i][reqField] == value) {
            return(container[i][resField]);
        }
    }
    return '';
}

Caso de uso:

var data=[{
            "id": 502100,
            "name": "Bərdə filialı"
        },
        {
            "id": 502122
            "name": "10 saylı filialı"
        },
        {
            "id": 503176
            "name": "5 sayli filialı"
        }]

console.log('Result is  '+findBySpecField(data,'id','502100','name'));

salida:

Result is Bərdə filialı
Musa
fuente
4
$scope.olkes = [{'id':11, 'name':'---Zəhmət olmasa seçim edin---'},
                {'id':15, 'name':'Türkyə'},
                {'id':45, 'name':'Azərbaycan'},
                {'id':60, 'name':'Rusya'},
                {'id':64, 'name':'Gürcüstan'},
                {'id':65, 'name':'Qazaxıstan'}];

<span>{{(olkes | filter: {id:45})[0].name}}</span>

salida: Azərbaycan

Celal Muhtar
fuente
2

Si puede, diseñe su estructura de datos JSON haciendo uso de los índices de la matriz como ID. Incluso puede "normalizar" sus matrices JSON siempre que no tenga problemas para utilizar los índices de la matriz como "clave principal" y "clave externa", algo así como RDBMS. Como tal, en el futuro, incluso puede hacer algo como esto:

function getParentById(childID) {
var parentObject = parentArray[childArray[childID].parentID];
return parentObject;
}

Esta es la solución "por diseño" . Para su caso, simplemente:

var nameToFind = results[idToQuery - 1].name;

Por supuesto, si su formato de ID es algo así como "XX-0001" del cual su índice de matriz es 0 , entonces puede realizar alguna manipulación de cadena para mapear el ID; de lo contrario, no se puede hacer nada al respecto, excepto mediante el enfoque de iteración.

Antonio Ooi
fuente
2

Sé que llegué demasiado tarde para responder, pero siempre es mejor aparecer en lugar de no aparecer :). ES6 forma de conseguirlo:

$http.get("data/SampleData.json").then(response => {
let id = 'xyz';
let item = response.data.results.find(result => result.id === id);
console.log(item); //your desired item
});
Hitesh Kumar
fuente
2

La forma simple de obtener (un) elemento de la matriz por id:

El método find () devuelve el valor del primer elemento de la matriz que satisface la función de prueba proporcionada. De lo contrario, se devuelve undefined.

function isBigEnough(element) {
    return element >= 15;
}

var integers = [12, 5, 8, 130, 160, 44];
integers.find(isBigEnough); // 130  only one element - first

no es necesario utilizar filter () y capturar el primer elemento xx.filter () [0] como en los comentarios anteriores

Lo mismo para los objetos en matriz.

var foo = {
"results" : [{
    "id" : 1,
    "name" : "Test"
}, {
    "id" : 2,
    "name" : "Beispiel"
}, {
    "id" : 3,
    "name" : "Sample"
}
]};

var secondElement = foo.results.find(function(item){
    return item.id == 2;
});

var json = JSON.stringify(secondElement);
console.log(json);

Por supuesto, si tiene una identificación múltiple, use el método filter () para obtener todos los objetos. Salud

function isBigEnough(element) {
    return element >= 15;
}

var integers = [12, 5, 8, 130, 160, 44];
integers.find(isBigEnough); // 130  only one element - first

var foo = {
"results" : [{
    "id" : 1,
    "name" : "Test"
}, {
    "id" : 2,
    "name" : "Beispiel"
}, {
    "id" : 3,
    "name" : "Sample"
}
]};

var secondElement = foo.results.find(function(item){
    return item.id == 2;
});

var json = JSON.stringify(secondElement);
console.log(json);

abosancic
fuente
0
    projectDetailsController.controller('ProjectDetailsCtrl', function ($scope, $routeParams, $http) {
    $http.get('data/projects.json').success(function(data) {

        $scope.projects = data;
        console.log(data);

        for(var i = 0; i < data.length; i++) {
        $scope.project = data[i];
        if($scope.project.name === $routeParams.projectName) {
            console.log('project-details',$scope.project);
        return $scope.project;
        }
        }

    });
});

No estoy seguro de si es realmente bueno, pero esto fue útil para mí. Necesitaba usar $ scope para que funcione correctamente.

Jordy
fuente
0

use $ timeout y ejecute una función para buscar en la matriz de "resultados"

app.controller("Search", function ($scope, $timeout) {
        var foo = { "results": [
          {
             "id": 12,
             "name": "Test"
          },
          {
             "id": 2,
             "name": "Beispiel"
          },
          {
             "id": 3,
            "name": "Sample"
          }
        ] };
        $timeout(function () {
            for (var i = 0; i < foo.results.length; i++) {
                if (foo.results[i].id=== 2) {
                    $scope.name = foo.results[i].name;
                }
            }
        }, 10);

    });
Moein Fazeli
fuente
0

Iteraría sobre la matriz de resultados usando un filtro angularjs como este:

var foundResultObject = getObjectFromResultsList (resultados, 1);

function getObjectFromResultsList(results, resultIdToRetrieve) {
        return $filter('filter')(results, { id: resultIdToRetrieve }, true)[0];
    }
por encima del tiempo
fuente