How to use AngularJS NG-repeat to display only distinct values from a dataset in an ng-repeat directive

I have a project that involves working with JSON data to display information using BootStrap Tabs categorized by different categories.

Sample JSON data:

"result": [
    {
        category: "A",
        price: "499.00",
        productName: "AAA",
        productConfig: {
            specs: "Lorem ipsum",
            creditAllowed: false,
            description: "blah blah",
            ...
        }
    },
    {
        category: "A",
        price: "479.00",
        productName: "AAB",
        productConfig: {
            specs: "Lorem ipsum",
            creditAllowed: true,
            description: "blah blah",
            ...
        }
    },
    {
        category: "B",
        price: "1299.00",
        productName: "BBB",
        productConfig: {
            specs: "Lorem ipsum",
            creditAllowed: true,
            description: "blah blah",
            ...
        }
    },
    {
        category: "A",
        price: "359.00",
        productName: "AXX",
        productConfig: {
            specs: "Lorem ipsum",
            creditAllowed: true,
            description: "blah blah",
            ...
        }
    },
]

To showcase this data, I need to utilize ng-repeat within my BootStrap tabs.

This is the desired layout:

https://i.sstatic.net/Xhvfk.png

The markup appearance:

<a load-data data-param="1">Load me</a>

A custom directive calls the service and stores all the data in a scope. The current element setup is as follows:

<ul class="nav nav-tabs col-lg-4 col-md-4" role="tablist">
    <li ng-repeat="data in tableData | unique: 'category'"><a href="#{{$index}}" role="tab" toggle="tab"></li>
</ul>


...

<div class="tab-content col-lg-8 col-md-8">
    <div role="tabpanel" class="tab-pane fade" id="{{$index}}" ng-repeat="contents in tableData | unique: 'category'">
         <h1>{{ contents.category }}</h1>
         <div class="tab-content-details">
             <table class="table">
                 <tr>
                     <td>{{ contents.price }}</td>
                     <td>{{ contents.productConfig.specs }}</td>
                     <td>{{ contents.productConfig.description }}</td>
                 </tr>
             </table>
         </div>
    </div>
</div>

However, the current code renders like this:

https://i.sstatic.net/O7yf4.png

Each category corresponds to one nav-link and one tab-pane. If a category has multiple products, the <table> should be on an ng-repeat, not the tab-pane.

An example of the ideal markup structure would look similar to this:

<ul class="nav nav-tabs col-lg-4 col-md-4" role="tablist">
    <li class="active"><a href="#0" role="tab" toggle="tab">Category A</li>
    <li><a href="#1" role="tab" toggle="tab">Category B</li>
    ...
</ul>


...

<div class="tab-content col-lg-8 col-md-8">
    <div role="tabpanel" class="tab-pane fade active" id="0">
         <h1>Category A</h1>
         <div class="tab-content-details">
             <table class="table">
                 <tr>
                     <td>499.00</td>
                     <td>Lorem ipsum</td>
                     <td>blah blah</td>
                 </tr>
                 <tr>
                     <td>479.00</td>
                     <td>Lorem ipsum</td>
                     <td>blah blah</td>
                 </tr>
             </table>
         </div>
    </div>
    <div role="tabpanel" class="tab-pane fade" id="1">
         <h1>Category B</h1>
         <div class="tab-content-details">
             <table class="table">
                 <tr>
                     <td>1299.00</td>
                     <td>Lorem ipsum</td>
                     <td>blah blah</td>
                 </tr>
             </table>
         </div>
    </div>
</div>

Is there a way to achieve this desired result while maintaining the current data structure? Thank you!

Answer №1

To begin with, it is important to target the tabs using their respective id's, assigning each tab the same id as data.category, rather than $index; Additionally, ensuring that toggle is changed to data-toggle is crucial for compatibility with bootstrap tabs:

<ul class="nav nav-tabs col-lg-4 col-md-4" role="tablist">
  <li ng-repeat="data in tableData | unique: 'category'">
     <a href="#{{data.category}}" role="tab" data-toggle="tab">
       Category {{ data.category }}         
     </a>  
  </li>
</ul>

Subsequently, implementing a nested ng-repeat based on the same unique criteria as above, utilizing ng-if to compare the main data category with the nested content categories:

<div class="tab-content col-lg-8 col-md-8">
  <div role="tabpanel" ng-repeat="data in tableData | unique: 'category'" class="tab-pane" id="{{data.category}}">
    <div ng-repeat="content in tableData">
      <div ng-if="content.category === data.category">
        {{ content | json }}
        <hr>
      </div>     
    </div>
  </div>  
</div>

Customizing the styling of each item according to your preference is now possible, where I have displayed the JSON data.

View demo here -> http://plnkr.co/edit/ZtZRA2im8Wxr1TaNWfkt?p=preview

Answer №2

 let app = angular.module("App", []);
                app.controller('AppCtrl',function($scope){
                        $scope.json_data ={ 
                        "results": [
    {
        category: "A",
        price: "499.00",
        productName: "AAA",
        productConfig: {
            specs: "Lorem ipsum",
            creditAllowed: false,
            description: "blah blah",
        }
    },
    {
        category: "A",
        price: "479.00",
        productName: "AAB",
        productConfig: {
            specs: "Lorem ipsum",
            creditAllowed: true,
            description: "blah blah",
        }
    },
    {
        category: "B",
        price: "1299.00",
        productName: "BBB",
        productConfig: {
            specs: "Lorem ipsum",
            creditAllowed: true,
            description: "blah blah",
        }
    },
    {
        category: "A",
        price: "359.00",
        productName: "AXX",
        productConfig: {
            specs: "Lorem ipsum",
            creditAllowed: true,
            description: "blah blah",
        }
    },
]
}               
                $scope.tableData_obj    = {}
                $scope.filterTxn        = {}
                $scope.json_data['results'].forEach(function(val){
                                if(val['category'] in  $scope.tableData_obj)
                                        return;
                                else
                                        $scope.tableData_obj[val['category']] = true;
                })
                $scope.tableData        = Object.keys($scope.tableData_obj)     
                $scope.own_filter       = function(values){
                        if(! $scope.filterTxn['values'])
                                return true;
                        if(values['category'] == $scope.filterTxn['values'])
                                return true
                        else
                                return false;   
                }
                $scope.update_filterTxn_values = function(data){
                        $scope.filterTxn['values'] = data;
                }
        })
li.ACTIVE{
                        background:green;
                 
                }
                li{
                        list-style-type:none;
                }
                li a{
                        cursor:pointer;
                }
                                li.ACTIVE a {
                                        color:white;
                                        font-weight:700;
                                }
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="App" ng-controller="AppCtrl ">
                <ul class="nav nav-tabs col-lg-4 col-md-4" role="tablist">
                        <li ng-repeat="data in tableData track by $index" ng-class="{'ACTIVE':filterTxn['values'] == data}"><a   ng-click="update_filterTxn_values(data)" role="tab" toggle="tab">{{'click_here to filter_data - '+data}}</a></li>

                </ul>
                <h1>{{'Selected Category - '+filterTxn['values']}}</h1>
                <div class="tab-content col-lg-8 col-md-8">
                    <div role="tabpanel" class="tab-pane fade" id="{{$index}}" ng-repeat="contents in json_data['results'] |filter:own_filter track by $index">
                         <h1>{{ contents.category }}</h1>
                         <div class="tab-content-details">
                             <table class="table">
                                 <tr>
                                     <td>{{ contents.price }}</td>
                                     <td>{{ contents.productConfig.specs }}</td>
                                     <td>{{ contents.productConfig.description }}</td>
                                 </tr>
                             </table>
                         </div>
                    </div>
                </div>

        </div>

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

Check the row in a JQuery table by using the .on("click") function to determine if a hyperlink within the row was clicked or if

I am in the process of building a website using the following libraries: Parse.js: 1.4.2 JQuery: 1.11.2 and 1.10.3 (U.I.) Twitter Bootstrap: 3.3.4 To demonstrate what I am trying to achieve, I have set up this JSfiddle with placeholder data: https://jsf ...

Simulating the Fourier Series

I've created a unique drawing app that transforms sketches into Fourier series, but it's exhibiting an unusual behavior where it spirals inwards unexpectedly. Strangely, all the constants within the series are of similar size, which I suspect is ...

Using node.js to import functions from another file

The code below is what I currently have: // app.js var exports = module.exports = {}; module.exports = function () { var exported = {}; .. exported.myFunction = function (data, callback) { .. } . ...

What are the semantics behind implementing Basic Authentication in AngularJS and Spring Boot?

Currently going through a tutorial that involves AngularJS and Spring Security. The AngularJS navigation controller triggers an authenticate function upon page load: var authenticate = function(credentials, callback) { var headers = credentials ? { ...

Select a Button to randomly choose another Button

I am currently developing a dynamic Bootstrap OnePage-Website using HTML, CSS, and JavaScript. The highlight of this website is the Team section where users can book appointments with one of three team members by clicking on a corresponding button beneat ...

Tips and tricks for concealing Windows security authentication with JavaScript

Experiencing a challenge in my code. Whenever I call a URL from the server application, it prompts for Windows security and displays a pop-up login. How can I use JavaScript to conceal this from my application? Does anyone have any suggestions? ...

Configuring JWT with Next.js and NextAuth seems to pose a challenge

Setting up JWT with NextAuth has been a bit of a challenge for me. I've been scouring GitHub posts and doing research, but haven't found much help. It seems like there's an error occurring when NextAuth tries to decode the JWT payload. All I ...

Restricting data display in AngularJS with $http and get()

Utilizing the $http service and itsget() method, I am able to access data from the database. Within the database there are 100 records organized in an array of objects; however, I am only interested in obtaining the first 10 records rather than all 100. H ...

What is the best way to access a DOM node within a withStyle component?

Currently, I am involved in a react project where my team and I are utilizing Material UI. I encountered a situation where I needed to access the DOM node of another component that was wrapped by a HOC. To achieve this, I attempted using ref in React but o ...

Is there a way to mask all communication with the bot and only display the ultimate outcome in Element Web Messenger?

I've been experimenting with the Matrix Element Web Messenger and came across a bot on GitHub (mautrix/whatsapp) that enables connection to Whatsapp. Rather than the traditional process of creating a room, sending a "login" message, and receiving a QR ...

JavaScript's static function and variable that operate asynchronously

Encountering an issue with a "static" function in JavaScript (Node.js server). User.create = function(data, _callback){ var node = db.createNode(data); var _user = new User(node); _user.save(function(err){ if(err) return callba ...

Incorporate a file into all API endpoints with Next.js API functionality

Is there a way to incorporate a "bootstrap" file (a file with side-effects) as the first file included in all Next.js APIs? The main issue is that I have a Winston logger in a file that needs to be added to every API endpoint, but this process hinders dev ...

Creating a POP UP feature using Angular and Node was a challenging yet rewarding task

Could someone share with me how to create a pop-up feature using Angular and Node.js? I would like the login page to pop up when the user clicks on the login button. Thank you! ...

Ways to differentiate between a desktop browser width of 1024px and a tablet width of 1024px with the help of jquery

So here's the issue I'm dealing with: I have scroll-based animation functions set up for desktop browsers, and different animations in place for tablet browsers. The challenge is to make these functions work on a desktop with a 1024px dimension. ...

Encountering a VueJS error with Google Cloud Logging Winston: "TypeError: The 'original' argument must be a Function."

I have been attempting to integrate @google-cloud/logging-winston into my VueJS project by closely following the guidelines provided in both the npm package and Google Cloud docs. However, I am encountering an error message stating "TypeError: The &q ...

Tips on deobfuscating Next.js HTML from online sources

I am faced with the task of reconstructing a website that I scraped from the internet using wget. It seems to be built on next js, based on the presence of the _next folder. Even though I have no experience with nextjs and do not understand its inner worki ...

What is the reason behind re-rendering pages specifically for error messages in express and nodejs?

In the world of web development, it is commonly accepted practice to re-render a page to display error messages and redirect to show success messages. While implementing this principle in my code using express js, I have encountered a few challenges. For ...

Error encountered while implementing Ajax in Django with XMLHttpRequest

Currently, I am developing a webpage with a form in the Django view. The form consists of input fields for an artist's name, city, and state. These values will eventually be combined to create a URL linking to a JSON file containing concert data (this ...

Using the 'gf' command in Vim to resolve JavaScript modules with a Webpack tilde alias

Recently, I joined a Vue.js project that makes use of the tilde (~) notation in module imports. For example: import WhateverApi from '~/api/whatever'; The project repository is a mix of various files including a Vagrant machine setup, a Laravel ...

"Utilizing AngularJS to asynchronously send an HTTP POST request and dynamically update

I've been working on an angularjs chat module and have come across a challenge. I developed an algorithm that handles creating new chats, with the following steps: Click on the 'New Chat' button A list of available people to chat with wil ...