Obtenha um objeto específico por id da matriz de objetos em AngularJS


111

Tenho um arquivo JSON contendo alguns dados que gostaria de acessar no meu site AngularJS. Agora o que eu quero é obter apenas um objeto da matriz. Então, eu gostaria, por exemplo, de Item com id 1.

Os dados são assim:

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

Eu gostaria de carregar os dados com a funcionalidade AngularJS $ http como esta:

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

que está funcionando. Mas como posso agora obter um objeto de dados específico (por id) do array que recebo $http.get?

Agradeço antecipadamente por sua ajuda.

Cumprimenta o marc


Você já experimentou? Se sim, podemos ver o que você descobriu?
simonlchilds

1
Bem, eu não tenho ideia de qual seria a melhor maneira de usar o AngularJS. O que eu não gosto é de iterar sobre o array e fazer igual no id. Talvez haja uma maneira melhor?
mooonli

Você deve contar com underscorejs ou bibliotecas semelhantes para tal processamento. AngularJS é uma estrutura MVVM e pode não ter uma API para isso.
Vijay Pande

@marcbaur - você tem que iterar o array. Mesmo que você use sublinhado ou algo semelhante, suas funções, nos bastidores, são apenas iterativas.
Adam,

1
adicione o código angular para isso
Ankush Kondhalkar

Respostas:


4

A única maneira de fazer isso é iterar no array. Obviamente, se você tiver certeza de que os resultados estão ordenados por id, você pode fazer uma pesquisa binária


46
... Eu realmente espero que depois de ler esta resposta as pessoas não pensem que é uma boa ideia classificar um array e fazer uma pesquisa binária. A pesquisa binária é inteligente , com certeza, mas apenas se a matriz já estiver classificada e, na realidade, for: 1. fácil de implementar incorretamente, 2. Mais difícil de ler se implementada de forma inadequada.
Ben Lesh,

4
Eu apreciaria muito se os downvoters pudessem motivar sua decisão.
Antonio E.

1
Por padrão, o tipo Array javascript tem o método find (). O método find () retorna o valor do primeiro elemento na matriz que satisfaz a função de teste fornecida.
abosancic

246

Usando a solução ES6

Para aqueles que ainda estão lendo esta resposta, se você estiver usando o ES6, o findmétodo foi adicionado em matrizes. Portanto, supondo a mesma coleção, a solução seria:

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

Eu iria totalmente para esta solução agora, já que está menos ligada ao angular ou qualquer outro framework. Javascript puro.

Solução angular (solução antiga)

Meu objetivo era resolver esse problema fazendo o seguinte:

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

Um exemplo 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


1
Na verdade, acho que sim! Depois de buscar o array, você pode usar a função $ filter para filtrar o item com o id correto.
flup

10
Esta deve ser a resposta aceita. Eu tinha a mesma pergunta na minha cabeça e esta resposta é a única que usa o AngularJS existente e não está reinventando a roda. E sim, está funcionando.
Zoran P.

4
1 por esta ser a resposta aceita. Melhor solução usando bibliotecas angulares.
Meki

1
Plunker com filtro em uma expressão: plnkr.co/edit/yc0uZejGqWTcUVKvI7Tq?p=preview
Aaron Roller

4
Esteja ciente de que os filtros localizam substrings que não diferenciam maiúsculas de minúsculas por padrão. Portanto, (foo.results, {id: 2}) retorna [{id: 12}, {id: 2}], {id: 222}] mas (foo.results, function (d) {return d.id == = 2;}) retorna [{id: 2}]
Ryan.lay

26

Para quem está olhando este post antigo, esta é a maneira mais fácil de fazer isso atualmente. Requer apenas um AngularJS $filter. É como a resposta de Willemoes, mas mais curta e 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" }

AVISO

Como @mpgn diz, isso não funciona corretamente . Isso trará mais resultados. Exemplo: quando você pesquisa 3, também pegará 23


1
também pegar a id: 24 12 222 2002 etc
mpgn

Eu pensaria que o [0]faria com que ele retornasse o primeiro resultado que encontrar da coleção, então só funcionaria se sua coleção fosse classificada e o objeto que você está procurando fosse o primeiro que ele encontrasse durante sua iteração. Por exemplo. se houver um id: 12 que vem antes de id: 2, ele retornará id: 12.
Roddy of the Frozen Peas

25

pessoalmente, eu uso o sublinhado para esse tipo de coisa ... então

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

então "a" seria a linha que você queria de seu array onde o id era igual a 2


1
Eu realmente amo o sublinhado, mas é pior ter outra biblioteca JavaScript?
genuínofafa

8
Observe que findpode potencialmente retornar vários objetos. Como queremos apenas um, podemos usar o findWhereque retorna apenas a primeira ocorrência (que sabemos ser a única ocorrência), por exemplo a = _.findWhere(results, {id: 2}).
gregoltsov

16

Só quero acrescentar algo à resposta de Willemoes . O mesmo código escrito diretamente dentro do HTML terá a seguinte aparência:

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

Assumindo que "resultados" é uma variável de seu FooController e você deseja exibir a propriedade "nome" do item filtrado.


@ Ena-Como verificar se o resultado do filtro não é nulo ou indefinido?
Abhijeet

Usei essa variante HTML porque tinha certeza de que existia um resultado. Tentei e se não der resultado o console não dá erro, simplesmente deixa o texto em branco. Se você precisar fazer alguma lógica se nenhum resultado for encontrado, então eu acho que o melhor caminho a seguir é a resposta de Willemoes (código js dentro do controlador). Nesse exemplo, você deve verificar em HTML se a variável single_object é nula ou indefinida.
Ena

2
{{(FooController.results | filter: {id: 1}) [0] .name}: true} - se alguém está procurando uma correspondência exata
George Sharvadze

12

Você pode usar ng-repeate escolher dados apenas se os dados corresponderem ao que você está procurando usando, ng-show por exemplo:

 <div ng-repeat="data in res.results" ng-show="data.id==1">
     {{data.name}}
 </div>    

2
Se seu array tiver mais do que um número trivial de itens, isso criará muitos escopos desnecessários que podem tornar seu aplicativo lento.
The DIMM Reaper

9

Você pode simplesmente fazer um loop sobre sua 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);

Se você não quiser escrever esses loops confusos, você pode considerar o uso de underscore.js ou Lo-Dash (exemplo no último):

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

8

Se você quiser a lista de itens como cidade com base no id do estado, use

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

7

Infelizmente (a menos que eu esteja enganado), acho que você precisa iterar sobre o objeto de resultados.

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

Pelo menos assim ele sairá da iteração assim que encontrar o id correspondente correto.


Por quê? Você tem algo para fazer o backup?
simonlchilds

11
Bem, você sabe o que ..? Acabei de reler o Javascript - as partes boas para contrariar o seu argumento e estou errado! Por todo esse tempo eu tenho feito errado! Isso não me causou nenhum problema ... ainda. Eu atualizei minha resposta.
simonlchilds

6

Por que complicar a situação? isso é simples, escreva alguma função 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'));

resultado:

Result is Bərdə filialı

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>

saída: Azərbaycan


2

Se possível, projete sua estrutura de dados JSON fazendo uso dos índices de array como IDs. Você pode até "normalizar" seus arrays JSON, contanto que não tenha problemas em usar os índices de array como "chave primária" e "chave estrangeira", algo como RDBMS. Como tal, no futuro, você pode até fazer algo assim:

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

Esta é a solução "By Design" . Para o seu caso, simplesmente:

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

Obviamente, se o formato do seu ID for algo como "XX-0001", cujo índice do array é 0 , você pode fazer alguma manipulação de string para mapear o ID; ou então nada pode ser feito a respeito, exceto por meio da abordagem de iteração.


2

Sei que é tarde demais para responder, mas é sempre melhor aparecer do que não aparecer :). Forma ES6 de obtê-lo:

$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
});

2

A maneira simples de obter (um) elemento da matriz por id:

O método find () retorna o valor do primeiro elemento na matriz que satisfaz a função de teste fornecida. Caso contrário, undefined é retornado.

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

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

você não precisa usar filter () e capturar o primeiro elemento xx.filter () [0] como nos comentários acima

O mesmo para objetos na 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);

Claro, se você tiver vários id, use o método filter () para obter todos os objetos. Felicidades

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);


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;
        }
        }

    });
});

Não tenho certeza se é realmente bom, mas foi útil para mim. Eu precisava usar $ scope para fazer funcionar corretamente.


0

use $ timeout e execute uma função para pesquisar no array "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);

    });

0

Gostaria de iterar sobre a matriz de resultados usando um filtro angularjs como este:

var foundResultObject = getObjectFromResultsList (resultados, 1);

function getObjectFromResultsList(results, resultIdToRetrieve) {
        return $filter('filter')(results, { id: resultIdToRetrieve }, true)[0];
    }
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.