Eliminating repetitions in Angular JS ng-options / ng-repeat

I currently have the following data stored in my JavaScript:

$scope.jsonmarkers = [{
    "name": "Jeff",
        "type": "Organisation + Training Entity",
        "userID": "1"
}, {
    "name": "Fred",
        "type": "Organisation + Training Entity",
        "userID": "2"
}];

When it comes to displaying this data in my HTML, I am using the following code snippet:

<select id="typeselect" multiple ng-options="accnts.type for accnts in jsonmarkers" ng-model="accnt" ng-change="changeaccnt(accnt.type)"></select>

My question is, how can I ensure that each type is only displayed once when using the ng-options directive?

Answer №1

If you want to eliminate duplicates, one option is to utilize the unique filter provided by AngularUI. You can find the source code here and easily integrate it into ng-options or ng-repeat.

For more information and resources on this topic, visit Unique & Stuff

Additionally, there seems to be a syntax error in the JSON structure.

Check out this Working Code

Html

<div ng-app="app">
    <div ng-controller="MainController">
        <select id="typeselect"  ng-options="accnts.type for accnts in jsonmarkers | unique:'type'" ng-model="accnt" ng-change="changeaccnt(accnt.type)" multiple></select>
    </div>
</div>

script

    var app = angular.module("app", []);

app.controller("MainController", function ($scope) {
    $scope.jsonmarkers = [{
        "name": "Jeff",
            "type": "Organisation + Training Entity",
            "userID": "1"
    }, {
        "name": "Fred",
            "type": "Organisation + Training Entity",
            "userID": "2"
    }];
});


app.filter('unique', function () {

    return function (items, filterOn) {

        if (filterOn === false) {
            return items;
        }

        if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
            var hashCheck = {}, newItems = [];

            var extractValueToCompare = function (item) {
                if (angular.isObject(item) && angular.isString(filterOn)) {
                    return item[filterOn];
                } else {
                    return item;
                }
            };

            angular.forEach(items, function (item) {
                var valueToCheck, isDuplicate = false;

                for (var i = 0; i < newItems.length; i++) {
                    if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
                        isDuplicate = true;
                        break;
                    }
                }
                if (!isDuplicate) {
                    newItems.push(item);
                }

            });
            items = newItems;
        }
        return items;
    };
});

Answer №2

I revised the response provided by NidhishKrishnan to ensure compatibility with nested objects.

For instance, consider the following data:

$scope.jsonmarkers = [{
    "name": "Jeff",
    "type": "Organisation + Training Entity",
    "userID": "1",
    "userData": {
        "hire reason":"training"
    }
}, {
    "name": "Fred",
    "type": "Organisation + Training Entity",
    "userID": "2"
    "userData": {
        "hire reason":"training"
    }
}];

This is the updated code snippet:

angular.module('ArtifactFeederApp.filters', [])

    .filter('unique', function () {
    return function (items, filterOn) {

        if (filterOn === false) {
            return items;
        }

        if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
            var hashCheck = {}, newItems = [];

            var extractValueToCompare = function (item) {
                if (angular.isObject(item) && angular.isString(filterOn)) {

                    var resolveSearch = function(object, keyString){
                        if(typeof object == 'undefined'){
                            return object;
                        }
                        var values = keyString.split(".");
                        var firstValue = values[0];
                        keyString = keyString.replace(firstValue + ".", "");
                        if(values.length > 1){
                            return resolveSearch(object[firstValue], keyString);
                        } else {
                            return object[firstValue];
                        }
                    }

                    return resolveSearch(item, filterOn);
                } else {
                    return item;
                }
            };

            angular.forEach(items, function (item) {
                var valueToCheck, isDuplicate = false;

                for (var i = 0; i < newItems.length; i++) {
                    if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
                        isDuplicate = true;
                        break;
                    }
                }
                if (!isDuplicate) {
                    if(typeof item != 'undefined'){
                        newItems.push(item);
                    }
                }

            });
            items = newItems;
        }
        return items;
    };
});

You can now utilize the following:

<div ng-controller="MainController">
    <select id="typeselect"  ng-options="accnts.type for accnts in jsonmarkers | unique:'userData.hire reason'" ng-model="accnt" ng-change="changeaccnt(accnt.type)" multiple></select>
</div>

With this implementation, you will only see training as a selectable option in the list.

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

Node/Express unexpectedly returning string instead of Array after parsing JSON file

Having difficulty parsing an empty (stringified) Array from a JSON file. Instead of returning an empty array, I am receiving a string. The initial set up of my JSON file is: "[]" I am storing the parsed data in a variable using File System let parsedOb ...

Creating a specialized pathway with variable inputs within the URL

As a Node beginner, I am facing a challenge with an Express exercise on dynamic routes. The task at hand is to create a route that can accept dynamic arguments in the URL path and respond with a quote from the respective author. Here's a snippet of th ...

Internal styles are effective, while external styles seem to be less efficient

For some reason, internal CSS is working fine, but external CSS just won't cooperate. I even tried using the code !important, but it's like it doesn't understand. I'm trying to incorporate a gallery into my website, but I've hit a ...

Modifying the variable value upon clicking

I need to update a variable value on click, in order to send the updated value via ajax and load data either in ascending or descending format. Below is the JavaScript section at top of the page. var sortDirection = '0'; Now, here is the corre ...

Customize your Vue 3 application with custom Axios functions for handling GET, PUT,

I am looking to enhance my use of axios by customizing the get, post, and put functions. After performing the axios.create() operation, I want every subsequent get operation to include a then and catch block. import axios from "axios"; export de ...

Having trouble assigning a value to the datapicker through the onchange event and the name attribute in the code below

const stateValues = { code: '', product: '', checked: 'false', jobCardNo: '', openDate: '', completionDate: '', serial: '', technicalNo: '', ...

What is the best way to selectively remove and then later reinsert two items from an array in

I am facing a scenario where I have two buttons and an array to work with. The buttons are labeled "OR" and "AND", and the array consists of 7 items in a Dropdown list. When the user clicks on the "OR" button, it should remove 2 items from the array. Co ...

Endless spinning using snap.svg

How do I make an SVG element rotate endlessly? Is there a way to make it rotate continuously without stopping? While Snap provides a way to rotate an SVG element by a specific amount, I want to know how to create an infinite rotation effect. Is there a so ...

Customizing Bootstrap styles when toggling

I have been working on incorporating a dark/light theme into my project. By creating a separate SCSS file that is imported after the main Bootstrap file, I was able to override certain core Bootstrap styles to achieve a dark/light mode. Now, I am facing th ...

Is it possible in Vuetify 2 to align the items within the expansion of a v-data-table with the headers of the main component?

I am currently working on rendering a v-data-table where the expandable section serves as a "panel" title and I want the data inside the expansion to align with the headers set at the root level. Despite my efforts, I have not been able to find a way in th ...

Function in React not being successfully passed down between functional components

I have been accustomed to using class components and now I am transitioning into functional components in order to become more proficient with hooks. However, I have encountered an issue where I am struggling to pass a function from one functional compone ...

Add data to a nested array with Vuex

Currently, I am facing a challenge with adding an object to a nested array in Vue using store / vuex. While I have successfully updated the main comments array with a mutation, I am struggling to identify the specific main comment to which the new reply ob ...

What is the process for re-calling the getStaticProps function?

I am working on implementing a language selector in my Next.js application. After switching languages, I would like Next to automatically fetch the data in the selected locale. Any ideas on how I can achieve this? Currently, I am fetching my data using Ge ...

What could be causing my data to undergo alterations when transitioning from a frontend form submission to a backend API?

In my experience with Next.js 13 and Prisma, I encountered a peculiar issue. I had set up a basic form to collect user information for an api request. Oddly enough, when I printed the data right before sending it, everything seemed fine. However, upon arri ...

Leverage information stored in an array within the HandsonTable Angular directive

Some of my columns in a HandsoneTable created using Angular directives are not rendering when I try to use an array as the data source with common array notation (name[0]). I'm unsure if this is supposed to work like this or if I am doing something wr ...

What is the method to extract a single user instead of a group of users?

I am attempting to transition from a list of users to displaying the profile of a single user on a separate page. My goal is to achieve this using routerLink and passing the specific user's id to the next page. Although the routing is functioning co ...

A beginner's guide to importing modules in Node.js

Whenever I attempt to import into my nodejs file, I consistently encounter the error message stating "cannot import outside a module." I have experimented with various solutions found on StackOverFlow, such as including "type":"module" ...

What are the specific circumstances that require us to manually $watch a scope variable in Angular?

Can someone help clarify when the scope variable is not automatically watched? Do I need to manually watch all the scope variables that are not specified in the template if I want to monitor their value changes? Thank you ...

Incorporating database coordinates into Marker React Leaflet: A Step-by-Step Guide

When I retrieve coordinates from the database, they are structured as "lat" and "lon" fields. In my mapping application, I have multiple markers to display. How can I combine these two fields to pass coordinates (coord.lat and coord.lon) to the Marker comp ...

ClassNames Central - showcasing a variety of class names for interpolation variables

Seeking guidance on creating a conditional statement to set the className for a div element. The conditional is functioning correctly, and I can see the className being assigned properly in the developer console. However, I am struggling to return it as ...