Отримати конкретний об'єкт за ідентифікатором з масиву об’єктів у AngularJS


111

У мене є файл JSON, який містить деякі дані, до яких я хочу отримати доступ на своєму веб-сайті AngularJS. Тепер я хочу отримати лише один об’єкт з масиву. Тому мені подобається, наприклад, Item with id 1.

Дані виглядають приблизно так:

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

Я хотів би завантажити дані з такою функцією AngularJS $ http:

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

яка працює. Але як я можу отримати певний об’єкт даних (за id) з масиву, з якого я отримую $http.get?

Заздалегідь дякую за вашу допомогу.

Вітає Марка


Ви самі дали йому піти? Якщо так, чи можемо ми побачити, що ви придумали?
simonlchilds

1
Ну, я не маю уявлення, який спосіб був би найкращим за допомогою AngularJS. Що мені не подобається - це перебирати масив і робити рівну на ідентифікатор. Може, є кращий спосіб?
mooonli

Для такої обробки слід покластися на підкреслювачі або подібні бібліотеки. AngularJS - це структура MVVM і може не мати api для цього.
Vijay Pande

@marcbaur - ви повинні повторити масив. Навіть якщо ви використовуєте підкреслення або щось подібне, його функції поза кадром просто повторюють.
Адам

1
додайте для цього кутовий код
Ankush Kondhalkar

Відповіді:


4

Єдиний спосіб зробити це - перебрати масив. Очевидно, якщо ви впевнені, що результати впорядковані за id, ви можете виконати двійковий пошук


46
... Я дуже сподіваюся, що прочитавши цю відповідь, люди не вважають, що це гарна ідея сортувати масив, а потім виконати двійковий пошук. Бінарний пошук розумний , напевно, але лише якщо масив вже відсортований, а насправді це: 1. легко втілити в життя, 2. важче читати, якщо погано реалізований.
Бен Леш

4
Я був би дуже вдячний, якби низовиди могли мотивувати своє рішення.
Антоніо Е.

1
За замовчуванням тип масиву javascript має метод find (). Метод find () повертає значення першого елемента в масиві, який задовольняє наданій функції тестування.
абосанчик

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)

Я б повністю зайнявся цим рішенням, оскільки менш прив’язаний до кутових чи будь-яких інших рамок. Чистий 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


1
Насправді, я думаю, це так і є! Після отримання масиву ви можете використовувати функцію $ filter для фільтрації елемента з правильним ідентифікатором.
Flup

10
Це має бути прийнятою відповіддю. У мене було те саме питання в голові, і ця відповідь є єдиною, яка використовує існуючий AngularJS і не винаходить колесо. І так, це працює.
Зоран П.

4
+1, тому що це прийнята відповідь. Найкраще рішення з використанням кутових бібліотек.
Мекі

1
Plunker з фільтром у виразі: plnkr.co/edit/yc0uZejGqWTcUVKvI7Tq?p=preview
Aaron Roller

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


1
також
спіймайте

Я думаю, що це [0]призведе до того, що він поверне перший результат, який він знайде з колекції, тому він буде працювати лише в тому випадку, якщо ваша колекція буде відсортована, а предмет, який ви шукаєте, є першим, який він знайде під час ітерації. Напр. якщо є id: 12, який передує id: 2, він поверне id: 12.
Roddy of the Frozen Peas

25

особисто я використовую підкреслення для подібних матеріалів ... так

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

тоді "a" - це рядок, який ви хотіли, для свого масиву, де id дорівнював 2


1
Я дуже люблю підкреслення, але чи гірше мати ще одну бібліотеку JavaScript?
truefafa

8
Зауважте, що findпотенційно можуть повертатися кілька об'єктів. Оскільки ми хочемо лише одного, ми можемо використовувати те, findWhereщо повертає лише перше виникнення (яке, як ми знаємо, є єдиним випадком), наприклад a = _.findWhere(results, {id: 2}).
грегольцов

16

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

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

Якщо припустити, що "результати" є змінною вашого FooController, і ви хочете відобразити властивість "name" відфільтрованого елемента.


@ Ena-Як перевірити результат фільтра не нульовим чи невизначеним?
Abhijeet

Я використовував цей варіант HTML, тому що я був впевнений, що результат існує. Я спробував, і якщо результату немає, консоль не видає помилок, вона просто залишає текст порожнім. Якщо вам потрібно зробити певну логіку, якщо результату не знайдено, я вважаю, що найкращим способом є відповідь Віллемоса (js-код всередині контролера). У цьому прикладі ви повинні перевірити в HTML, чи змінна single_object є нульовою чи невизначеною.
Ена

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
Якщо у вашому масиві більше тривіальної кількості елементів, це створить безліч непотрібних областей, які можуть уповільнити вашу програму.
Жниварка DIMM

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]

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

Принаймні таким чином він вирветься з ітерації, як тільки знайде правильний ідентифікаційний номер.


Чому? Чи є у вас щось на цьому?
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ı

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 до тих пір, поки у вас не виникне проблем із використанням індексів масиву як «первинний ключ» та «зовнішній ключ», щось на зразок RDBMS. Таким чином, у майбутньому ви навіть можете зробити щось подібне:

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

Це рішення "За задумом" . Для вашого випадку просто:

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 () повертає значення першого елемента в масиві, який задовольняє наданій функції тестування. Інакше невизначений повертається.

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


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

    });
});

Не впевнений, чи справді це добре, але це було для мене корисною. Мені потрібно було використовувати $ range, щоб він працював належним чином.


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];
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.