Получить конкретный объект по идентификатору из массива объектов в AngularJS

111

У меня есть файл JSON, содержащий некоторые данные, к которым я хотел бы получить доступ на моем веб-сайте AngularJS. Теперь я хочу получить только один объект из массива. Так что я бы хотел, например, Item с id 1.

Данные выглядят так:

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

Я хотел бы загрузить данные с помощью функции AngularJS $ http следующим образом:

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

который работает. Но как мне теперь получить конкретный объект данных (по идентификатору) из массива, из которого я получаю $http.get?

Заранее спасибо за вашу помощь.

Приветствует Марка

Mooonli
источник
Вы сами попробовали? Если да, то можем ли мы увидеть, что вы придумали?
simonlchilds
1
Я понятия не имею, какой путь лучше всего использовать с AngularJS. Что мне не нравится, так это перебирать массив и делать равные по идентификатору. Может есть способ получше?
mooonli
Вы должны полагаться на underscorejs или аналогичные библиотеки для такой обработки. AngularJS - это фреймворк MVVM, и для этого может не быть API.
Виджай Панде
@marcbaur - вам нужно перебрать массив. Даже если вы используете подчеркивание или что-то подобное, его функции за кулисами просто повторяются.
Адам,
1
пожалуйста, добавьте угловой код для этого
Анкуш Кондхалкар

Ответы:

4

Единственный способ сделать это - перебрать массив. Очевидно, если вы уверены, что результаты упорядочены по идентификатору, вы можете выполнить двоичный поиск

Антонио Э.
источник
46
... Я очень надеюсь, что после прочтения этого ответа люди не подумают, что сортировать массив, а затем выполнять двоичный поиск - хорошая идея. Двоичный поиск , конечно, умен , но только если массив уже отсортирован, а в действительности: 1. его легко плохо реализовать, 2. труднее читать, если он плохо реализован.
Бен Леш
4
Я был бы очень признателен, если бы те, кто проголосовал против, могли мотивировать свое решение.
Антонио Э.
1
По умолчанию тип массива javascript имеет метод find (). Метод find () возвращает значение первого элемента в массиве, который удовлетворяет предоставленной функции тестирования.
abosancic
246

Использование решения ES6

Для тех, кто все еще читает этот ответ, если вы используете ES6, findметод был добавлен в массивы. Итак, предполагая ту же коллекцию, решение будет:

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

Я бы полностью выбрал это решение сейчас, поскольку оно менее привязано к angular или любой другой структуре. Чистый Javascript.

Угловое решение (старое решение)

Я стремился решить эту проблему, выполнив следующие действия:

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

Пример использования:

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
источник
1
На самом деле, я думаю, да! После получения массива вы можете использовать функцию $ filter, чтобы отфильтровать элемент с правильным идентификатором.
flup
10
Это должен быть принятый ответ. У меня в голове возник тот же вопрос, и это единственный ответ, который использует существующий AngularJS и не изобретает колесо. И да, это работает.
Zoran P.
4
+1 за то, что это принятый ответ. Лучшее решение с использованием угловых библиотек.
Meki
1
Plunker с фильтром в выражении: plnkr.co/edit/yc0uZejGqWTcUVKvI7Tq?p=preview
Аарон Роллер
4
Имейте в виду, что фильтры по умолчанию находят подстроки без учета регистра. Итак (foo.results, {id: 2}) возвращает [{id: 12}, {id: 2}], {id: 222}], но (foo.results, function (d) {return d.id == = 2;}) возвращает [{id: 2}]
Ryan.lay
26

Для всех, кто просматривает этот старый пост, это самый простой способ сделать это на данный момент. Для этого требуется только AngularJS $filter. Это похоже на ответ Виллемоса, но короче и легче для понимания.

{ 
    "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" }

ПРЕДУПРЕЖДЕНИЕ

Как говорит @mpgn, это не работает должным образом . Это даст больше результатов. Пример: при поиске 3 будет найдено и 23

Тиллман32
источник
1
также catch id: 24 12 222 2002 и т. д.
mpgn
Я бы подумал, что это [0]приведет к тому, что он вернет первый результат, который он найдет в коллекции, поэтому он будет работать только в том случае, если ваша коллекция отсортирована, а объект, который вы ищете, будет первым, который он найдет во время своей итерации. Например. если перед id: 2 стоит id: 12, он вернет id: 12.
Родди из Frozen Peas
25

лично я использую подчеркивание для такого рода вещей ... так что

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

тогда "a" будет той строкой, которую вы хотели в своем массиве, где идентификатор был равен 2

Джейсон Бёрнер
источник
1
Мне очень нравится подчеркивание, но разве еще хуже иметь другую библиотеку JavaScript?
originalfafa
8
Обратите внимание, что findпотенциально может возвращать несколько объектов. Поскольку нам нужен только один, мы можем использовать, findWhereкоторый возвращает только первое вхождение (которое, как мы знаем, является единственным вхождением), например a = _.findWhere(results, {id: 2}).
gregoltsov
16

Я просто хочу добавить кое-что к ответу Виллемоса . Тот же код, написанный непосредственно внутри HTML, будет выглядеть так:

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

Предполагая, что «результаты» - это переменная вашего FooController, и вы хотите отобразить свойство «имя» фильтруемого элемента.

Эна
источник
@ Ena-Как проверить, что результат фильтра не равен нулю или не определен?
Abhijeet
Я использовал этот вариант HTML, потому что был уверен, что результат есть. Я попробовал, и если результата нет, консоль не выдает ошибок, просто текст остается пустым. Если вам нужно выполнить некоторую логику, если результат не найден, я думаю, что лучший способ - это ответить Виллемо (код js внутри контроллера). В этом примере вы должны затем проверить в HTML, имеет ли переменная single_object значение null или undefined.
Ena
2
{{(FooController.results | filter: {id: 1}) [0] .name}: true} - если кто-то ищет точное совпадение
Георгий Шарвадзе
12

Вы можете использовать ng-repeatи выбирать данные только в том случае, если данные соответствуют тому, что вы ищете, ng-show например:

 <div ng-repeat="data in res.results" ng-show="data.id==1">
     {{data.name}}
 </div>    
Джеймс Кута Симию
источник
2
Если ваш массив имеет более чем тривиальное количество элементов, это создаст много ненужных областей, которые могут замедлить работу вашего приложения.
The DIMM Reaper
9

Вы можете просто перебрать свой массив:

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

Если вы не хотите писать эти беспорядочные циклы, вы можете рассмотреть возможность использования underscore.js или Lo-Dash (пример последнего):

var doc_id_2 = _.filter(doc.results, {id: 2})[0]
kamituel
источник
8

Если вам нужен список элементов, таких как город, на основе идентификатора состояния, используйте

var state_Id = 5;
var items = ($filter('filter')(citylist, {stateId: state_Id }));
Али Адрави
источник
7

К сожалению (если я не ошибаюсь), я думаю, вам нужно перебрать объект результатов.

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

По крайней мере, таким образом он выйдет из итерации, как только найдет правильный соответствующий идентификатор.

simonlдети
источник
Зачем? У вас есть что-нибудь в подтверждение этого?
simonlchilds
11
Ну знаете что ..? Я просто пошел перечитывать Javascript - хорошие части , чтобы противостоять вашим аргументам , и я буду не прав! Все это время я делал это неправильно! Но это не вызвало у меня никаких проблем ... пока. Я обновил свой ответ.
simonlchilds
6

Зачем усложнять ситуацию? это просто напишите какую-нибудь функцию вроде этой:

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

Пример использования:

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

вывод:

Result is Bərdə filialı
Musa
источник
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>

вывод: Azərbaycan

Джелал Мухтар
источник
2

По возможности спроектируйте структуру данных JSON, используя индексы массива в качестве идентификаторов. Вы даже можете «нормализовать» свои массивы JSON, если у вас нет проблем с использованием индексов массива в качестве «первичного ключа» и «внешнего ключа», что-то вроде РСУБД. Таким образом, в будущем вы даже можете сделать что-то вроде этого:

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

Это решение «By Design» . В вашем случае просто:

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

Конечно, если ваш формат идентификатора похож на «XX-0001», индекс массива которого равен 0 , тогда вы можете либо выполнить некоторые операции со строкой, чтобы сопоставить идентификатор; иначе с этим ничего нельзя поделать, кроме итерационного подхода.

Антонио Оои
источник
2

Я знаю, что слишком поздно отвечать, но всегда лучше появиться, чем не появляться вообще :). ES6 способ получить это:

$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

Простой способ получить (один) элемент из массива по id:

Метод find () возвращает значение первого элемента в массиве, который удовлетворяет предоставленной функции тестирования. В противном случае возвращается undefined.

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

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

вам не нужно использовать filter () и ловить первый элемент xx.filter () [0], как в комментариях выше

То же самое для объектов в массиве

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

Конечно, если у вас несколько идентификаторов, используйте метод filter (), чтобы получить все объекты. ура

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
источник
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;
        }
        }

    });
});

Не уверен, что это действительно хорошо, но это было полезно для меня ... Мне нужно было использовать $ scope, чтобы он работал правильно.

Джорди
источник
0

используйте $ timeout и запустите функцию для поиска в массиве "результатов"

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

Я бы перебирал массив результатов, используя фильтр angularjs следующим образом:

var foundResultObject = getObjectFromResultsList (результаты, 1);

function getObjectFromResultsList(results, resultIdToRetrieve) {
        return $filter('filter')(results, { id: resultIdToRetrieve }, true)[0];
    }
abovetempo
источник