Tips for refining a JSON object by a nested value within the second object in Angular, all while avoiding the use of ng-if or ng-show

I am a beginner in Angular and Ionic, currently developing an Ionic application that displays assets retrieved as JSON through an angular data service. My goal is to apply a second-level filter on my "asset" data using a separate list of "groups," where each group object contains the IDs of assets that belong to that specific group. This additional filter will refine the data shown in the view by only displaying assets that are part of the selected group.

Below is a simplified structure of my two objects:

"assets": [
    {"id": 1, "deviceName": "vehicle 1", "vRoadSpeed": 40},
    {"id": 2, "deviceName": "vehicle 2", "vRoadSpeed": 50},
    {"id": 3, "deviceName": "vehicle 3", "vRoadSpeed": 40}
]

and

"groups":[
        {"id": 1, "name": "downtown", "members": [{"id": 1},{"id": 2}]},
        {"id": 2, "name": "west", "members": [{"id": 1},{"id": 3}]}, 
        {"id": 3, "name": "east", "members": [{"id": 1}]}
]

My aim is to filter the values in the "assets" array based on its id, which should match the nested "members" id in the corresponding group from the second object. For example, selecting group id 3 ("east") would result in returning asset 1, "vehicle 1" from the "assets" array.

Here's what I have coded so far:

Controller:

.controller("AssetListCtrl",['$scope', 'dataService', function($scope, dataService){
    var assets = [];
    var groups = [];

    dataService.getAssets().then(function(assets){
        $scope.assets = assets;
    })

    dataService.getGroups().then(function(groups){
        $scope.groups = groups;
    }),

    $scope.filterFunction = function(element){
        return element.name.match(/^Ma/) ? true : false;
    };
}])

Directive:

.directive('testDirective',function(){
    return{
        controller: 'AssetListCtrl',
        replace: true,
        link: function(scope, element, attrs){

            scope.selectedGroups = {};
            scope.noGroupsSelected = true;

            scope.filterByGroup = function(){
                angular.forEach(scope.assets, function(asset){
                    var match = false;
                    angular.forEach(asset.groups, function(g) {
                        if (scope.selectedGroups[g.id]){
                            match = true;
                        }
                    });
                    asset.matchesGroup = match;
                });
                scope.noGroupsSelected = true
                angular.forEach(Object.keys(scope.selectedGroups), function(k) {
                    if (scope.selectedGroups[k]) {
                        scope.noGroupsSelected = false;
                    }
                });
            }
        }
    }
})

Data Service:

 .factory('dataService', function($http){
        var assets = {};
        var groups = {};
        
        return {
            getAssets: function(){
                return $http.get('../lib/data/sampleData.json').then(function(response){
                    assets = response.data.assets; //populate variable 'assets'
                    return response.data.assets;
                });
            },
            getAsset: function(index){
                return assets[index];
            },
            getGroups: function(){
                return $http.get('../lib/data/sampleData.json').then(function(response){
                    groups = response.data.groups; //populate variable 'groups'
                    return response.data.groups;
                });
            }
        }
    })

HTML:

<div test-directive>
    Groups:
    <div ng-repeat = "group in groups">
        <label>
            <input type="checkbox" ng-model="selectedGroups[group.id]" name="groups_group" ng-change="filterByGroup()">{{group.name}} 
        </label>
    </div>
    <br>Assets
    <div class="content wrapper" infinite-scroll="addMoreItems()" infinite-scroll-distance="2">
        <ion-item ng-repeat="asset in filteredAssets = (assets | filter: query) | limitTo: config.itemsDisplayedInList track by asset.id" ng-if="asset.matchesGroup || noGroupsSelected" ui-sref='app.AssetListDetail({index: $index})'>
            <div class = "row">
                {{asset.deviceName}}
            </div>
        </ion-item>
    </div>
</div>

(Please note that I am exploring ways to implement infinite scroll based on recommendations found at: . As per advice found in How to improve performance of ngRepeat over a huge dataset (angular.js)?, although Ionic's 'collectionRepeat' directive is known for its efficiency, it may not be compatible with 'ng-show' and 'ng-if', hence omitted here)

The concept I am trying to achieve aligns with the approach discussed in this post: Angular JS - Creating a filter to compare 2 arrays. While I have successfully implemented the provided code snippet, I also need to incorporate a second filter on the data (like a general search field). However, combining a filter with ng-show might not be recommended (Get the length of list shown by ng-Show-via substitution with ng-if). How can I navigate around this limitation?

I welcome all suggestions and feedback regarding data structure and the coding approach.

Answer №1

After receiving some clarification on filtering objects based on nested values in a second JSON object, I thought it would be helpful to share my insights.

Here is the structure of the JSON data:

{
   "assets": [
        {
            "deviceName": "vehicle 25",
            "vpkDeviceID": 352964050744425,
            "driverName": "Mike Smith"
        },
        {
            "deviceName": "vehicle 52",
            "vpkDeviceID": 352599041910352,
            "driverName": "John Doe"
        },
        {
            "deviceName": "vehicle 11",
            "vpkDeviceID": 862170016156711,
            "driverName": "Sarah Johnson"
        },
        {
            "deviceName": "vehicle 28",
            "vpkDeviceID": 862193020453528,
            "driverName": "Eleanor Petit"
        }
    ],
    "groups":
        [
            {"ID": 1, "name": "nairobi", "members": [{"vpkDeviceID": 352964050744425}, {"vpkDeviceID": 352599041910352}, {"vpkDeviceID": 862170016156711}]}, 
            {"ID": 2, "name": "karen", "members": [{"vpkDeviceID": 352964050744425}, {"vpkDeviceID": 352599041910352}]}, 
            {"ID": 3, "name": "langata", "members": [{"vpkDeviceID": 352599041910352}, {"vpkDeviceID": 862170016156711}, {"vpkDeviceID": 862193020453528}]},
            {"ID": 4, "name": "downtown", "members": [{"vpkDeviceID": 352964050744425}, {"vpkDeviceID": 862170016156711}]}, 
            {"ID": 5, "name": "westlands", "members": [{"vpkDeviceID": 862193020453528}]}
        ]
}

In HTML, the filter is structured as follows:

<form action="">
    Group:
    <select name="groups" id="grp" ng-model="selectedGroup" ng-options="group.name for group in groups">
        <option value="">Select All</option>
    </select>
</form>

<div>
    <div ng-repeat="asset in assets | filter: myFilter">
        {{asset.driverName}}
    </div>
</div>

The filter function in the controller looks like this:

$scope.myFilter = function(val, i, a) {
    if (!$scope.selectedGroup) {
        return true;
    };
    var m = false;
    var grp = $scope.selectedGroup;
    angular.forEach(grp.members, function(v, k) {
        if (val.vpkDeviceID == v.vpkDeviceID) {
            m = true;
        }
    }, m);
    return m;
};
$scope.selectedAsset = {};
$scope.selectedGroup = null;

You can view the working example here. No need for ng-if or ng-show.

I want to thank @jb-nizet for his help clarifying a related question, which led me to optimize my code for filtering using ng-options. This approach proved to be cleaner and more efficient. Please refer to the post for more details on the restructuring process.

Note that I initially inquired about both filtering methods and performance optimization. I have decided to focus solely on the filtering aspect here and keep performance-related discussions separate.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The ngClass directive did not expect the token '=='

Hey everyone, I'm currently facing an issue while trying to use multiple expressions in my ng-class directive. Unfortunately, the browser console is throwing this error: Error: [$parse:syntax] Syntax Error: Token '==' is unexpected, expecti ...

Adjust the height in proportion to the width

My goal is to adjust the height of the li's based on their width using JQuery. var width = $('li').width(); $('li').css('height', width + 'px'); However, I've encountered an issue as it doesn't resu ...

Upon clicking on a different div, a div will elegantly slide down from above the footer

I'm struggling with sliding a div from the bottom of the page. Here is my JSFIDDLE Currently, when I click on the blue box (arrow-hover), the div slides up (box-main). However, to hide the div (box-main) again, I have to click inside the box-main d ...

Does the sequence matter when studying JavaScript, Ajax, jQuery, and JSON?

Expanding my job opportunities is a top priority for me, which is why I am dedicated to learning JavaScript, AJAX, jQuery, and JSON. As I delve into these languages, I can see how they all have roots in JavaScript. My main inquiry is about the relationsh ...

Chaining Assignments in TypeScript

let a: { m?: string }; let b = a = {}; b.m = ''; // Property 'm' does not exist on type '{}'. let a: { m?: string } = {}; let b = a; b.m = ''; // It's OK Link to TypeScript Playground What occurs ...

Changing the value within a deeply nested object

I am facing an issue with a nested object in my code: { id: "id", name: "Name", type: "SC", allgemein: { charname: "Name", spieler: "Jon", }, eigenschaften: { lebenspunkte: "30", }, talente: {}, zauber ...

Utilize Botium Scripting Memory Variables to Enhance Asserter Functionality

Consider the following test.convo.text example: Test asserter #me Show my json #bot $json MY-CUSTOM-ASSERTER $json The asserter recognizes '$json' string as arguments. I need the JSON response from the bot to be passed as arguments. Is the ...

Dealing with lag in Kendo Grid (Utilizing Kendo Grid, Angular JS, and Web API)

Query : I have integrated a Kendo Grid into my Angular JS HTML page. The data for the Kendo Grid is fetched from a remote service Web API. While paging through the Kendo Grid, it attempts to download a whopping 38 MB of content for every 10 records, taki ...

The server-to-server POST request is experiencing errors and delivering inaccurate information

I am facing an issue where the JSON data sent from my webhook receiving server to my database server is not being processed correctly. The logs show 'none', indicating a problem with the JSON formatting. Here is a snippet of the test client file ...

unable to choose the radio option

Encountering an unusual problem with the radio buttons due to custom styling. The issue arises when trying to select certain options. Here is the jsfiddle link for reference: http://jsfiddle.net/bm6Lfhdz/1/ Attempt to choose 'Yes' from the secon ...

Troubleshooting issue: aria-expanded not functioning properly in a Next.js application

Summary: In a standard index file using Tailwind CSS, a button functions properly. However, when attempting to implement it in a Next.js project with TypeScript files, issues arise with the @click and aria-expanded attributes. Challenge: The specific prob ...

What is the process for using node js to upload a file?

After researching and going through several tutorials, I'm struggling with uploading a file using node/express. I have a feeling that something is not right on either the HTML or JQuery side of things. The tutorial I am following is here. However, wh ...

It appears that the data in nodejs is not being displayed correctly by res.json

I am currently developing APIs using a local file named ads.js. The main API /api/ads that displays all the ads in JSON format is functioning correctly. However, the secondary API /api/ads/:id does not seem to be returning any data. The server is being r ...

Put the values into an array format for each key within an object using JavaScript

I am attempting to transform an array containing email addresses into an object. How can I insert values in the value array for a single key? var list = [ "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6903060107291008010 ...

JavaScript validation code for verifying hostnames with a specified domain name

I need a customized validation check for my order form where users are asked to enter their server hostname. The challenge is that I'm using WHMCS with encrypted PHP code and IonCube loaders, making it difficult to add this check. Users can input any ...

Error in AngularJS Unit Test: Unidentified function caused the issue

I am delving into the realm of unit testing in Angular. Starting off by writing tests for my controllers and then moving on to testing my services. Initially, I began with a simple test. This is the controller code: angular.module('app') .co ...

What is the Best Framework for Simplified JSON Compliance with CodeSmith?

After securing a copy of CodeSmith 5.2 just as I began working on an ASP.NET web development project, I saw the opportunity to merge the two. The website will require JSON based elements (either jQuery or ExtJS) for search/dropdown functionalities. Upon ...

Guide on displaying a real-time "Last Refreshed" message on a webpage that automatically updates to show the time passed since the last API request

Hey all, I recently started my journey into web development and I'm working on a feature to display "Last Refreshed ago" on the webpage. I came across this website which inspired me. What I aim to achieve is to show text like "Last Refreshed 1 sec ago ...

Encountering a MODULE NOT FOUND error when using express.js

const express = require("express"); const app = express(); const path = require("path"); app.use(express.static(staticPath)); let staticPath=path.join(__dirname, ".."); There seems to be an error in these lines of ...

How to retrieve a value from a Map that contains either zero or one entry?

I currently have a Map object with the possibility of containing zero or one entry. Here's an example: class Task { constructor( public id:string, public name:string, public description: string ) {} } const task1 = new Task('1', ...