Creating organized lists in Angular 4 using list separators

I'm struggling to organize a list with dividers between categories to group items accordingly. Each divider should be labeled with the month name, and the items under it should correspond to that specific month.

My Goal:

- August
  - item 1
  - item 2
- September
  - item 3
  - item 4
  - item 5

Each list item includes a date timestamp from which I extract the month information.

My Attempts:

export class PostItemService {
  groupedItems = [];

  // second item is the date timestamp
  items: item[] = [
    new item('cool title', 1503469292, 'some cool text'),
    new item('second title', 1503469292, 'some cool text'),
    new item('third title', 1503469292, 'some cool text'),
  ];

  splitOnMonth() {

    const items = this.items;
    const groupedItem = [];

    // extract the month number
    function convertTimeStamp(timestamp) {
        const date = new Date(timestamp * 1000);
        const monthNumber = date.getMonth() + 1;

        return monthNumber;
    }

   items.forEach((value, index) => {

      const myMonth = convertTimeStamp(value.date);

      // Stuck at this point, unsure how to proceed

   });

  } // splitOnMonth()

}

I've experimented with various approaches, but I haven't found a solution yet. My main roadblock is determining the next steps from here.

If anyone has faced and resolved a similar challenge or can offer guidance on this issue, I would greatly appreciate it.

Thank you in advance.

Answer №1

To organize your items by month, you can create a map of month objects where each object contains the month's name and an array of items belonging to that month. Iterate through your items, identify their respective months, and push them into the corresponding month's array (creating the object if needed). In your template, iterate through the month array and display items only if they have subitems.

For more details and code examples, please check out this Plunkr link - here


export class PostItemService {

   monthMap: { [index: number]: { monthName: string, items: item[] }};
   monthArray: any[] = [];

   items: item[] = [
      new item('cool title', 1503469292, 'some cool text'),
      new item('second title', 1503469292, 'some cool text'),
      new item('third title', 1503469292, 'some cool text'),
   ];

   constructor() {
       this.monthMap = {  
           1: { monthName: 'January', items: [] },
           2: { monthName: 'February', items: [] },
           3: { monthName: 'March', items: [] },
           // ...rest of the months
       };

       this.splitOnMonth();
   }

   splitOnMonth() {

     var convertTimeStamp = (timestamp) => {
         const date = new Date(timestamp * 1000);
         const monthNumber = date.getMonth() + 1;
         return monthNumber;
     }

     items.forEach((value, index) => {

          const myMonth = convertTimeStamp(value.date);

          this.monthMap[myMonth].items.push(value);
     });

     for (let prop in monthMap) {
        if (this.monthMap[prop].items.length > 0) {
            this.monthArray.push(this.monthMap[prop]);
        }
     }
  }  

}

In a component's template...

<ul class="month-groups">
   <li *ngFor="let month of this.monthArray">
       {{ month.monthName }} 
        <ul class="month-items">
            <li *ngFor="let item of month.items">
                 {{ item.value }}
             </li>
        </ul>
   </li>
</ul>

Remember to style your lists appropriately and consider adding extra margin for nested ones.

Note that there was a missing fat arrow in the forEach function. Additionally, it's advisable to minimize logic in constructors for Angular components. Testing methods like splitMonth() is fine in services but not in components with associated views.

Answer №2

If you're looking to enhance the functionality of your application, consider implementing a Pipe for this purpose.

Take a look at this example:

    @Pipe({
      name: 'ItemsFilterPipe',
      pure: false
    })
    export class ItemsFilterPipe implements PipeTransform {
      transform(items: Item[]): FilteredItem[] {
        // Customize your data processing here, such as creating a new object with timestamp as key and item as value
      }
    }

Then, you can utilize it like this:

*ngFor="let item of items | ItemsFilterPipe"

When used in ngFor, the item will contain {"timestamp": Item[]} pairs.

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

Should Angular libraries be developed using Typescript or transpiled into JavaScript?

Currently, I am in the process of developing a library that will be available as an Angular module through npm. The library itself has been written using typescript. Everything was functioning perfectly up until Angular version 5.0.0, but after this update ...

Angular Service Worker enhancements across various domains

Scenario Our team is currently developing an Angular application that is accessible through multiple domains. Depending on the domain, the app will display different colors and content, but it is essentially the same Angular application. To enhance perfo ...

Monitor the closure of a programmatically opened tab by the user

Currently, I am in the process of developing a web application using Angular 11 that interacts with the msgraph API to facilitate file uploads to either onedrive or sharepoint, and subsequently opens the uploaded file in the Office online editor. Although ...

Tips on revealing TypeScript modules in a NodeJS environment

Currently, I am working on developing a TypeScript library. My goal is to make this library compatible with both TypeScript and JavaScript Node projects. What would be the most effective approach for achieving this? Should I create two separate versions ...

Distributing a library of components using Vite, Vue 3, and Typescript to npm

My current challenge involves publishing a Vue 3 component library with Vite, all written in Typescript. The issue I'm facing is that the type definitions are not being included in the package when imported into another project. Upon importing the co ...

Error in Typescript: The type 'string' cannot be assigned to the type '"allName" | `allName.${number}.nestedArray`' within the react hook form

Currently, I am tackling the react hook form with typescript and facing a challenge with my data structure which involves arrays within an array. To address this, I decided to implement the useFieldArray functionality. allName: [ { name: "us ...

Vue3 and Ionic combined to create a Component that became a reactive object in Vue

Vue is issuing a warning about receiving a Component as a reactive object, which can cause unnecessary performance overhead. The warning suggests using markRaw or shallowRef instead of ref to avoid this issue. However, in my code, I am not explicitly using ...

I'm facing an issue where I am unable to commit the Angular folder in my project using IntelliJ or SourceTree with

I am currently working on a web app project that includes a folder with a PHP API REST and another folder with Angular files. Strangely, when I try to commit my files to BitBucket, everything gets committed except the files under the Angular folder. Simil ...

Type inference in TypeScript with transitivity

Consider this code snippet for illustration: function foo(t: "number"): number function foo(t: "string"): string function foo(t: "boolean"): boolean function foo(t: "number" | "string ...

Migration of Angular dynamic forms project - The error "input" does not have an initializer or a constructor, and another issue with Type T | undefined

Angular dynamic forms project migration - encountering Type T | undefined error In my quest to find a sample project demonstrating the creation of Angular forms using JSON datasets, I stumbled upon this repository: https://github.com/dkreider/advanced-dyn ...

React Type Mutation response feedback is a valuable tool for receiving input

I am facing an issue with passing the mutation success response in my code. I have a file named change-email.tsx which calls a component file updateEmail.tsx containing a mutation function. The submit function is working fine, but I cannot figure out how t ...

Ensure that parameters are validated correctly in the Next.JS application router using the searchParams method

When building the page, I need to properly validate params in the Next.JS app router using searchParams. My goal is to show a main image (coverImage) for each photo on the /gallery page. When a photo is clicked, I want to display more photos of the same k ...

An issue has been identified with React's HTML input maxLength feature where it does not display an error

Within my form, I have an input field that currently does not include validation for a maximum length. <input type="text" className="form-control" id="company" onBlur= ...

Error encountered while running "ionic cordova run android" command

Recently, I revisited my Ionic Cordova app after a few months and encountered an unexpected dependency issue when attempting to make a minor adjustment to the app. Although the app previously functioned correctly, even reverting all changes failed to addre ...

Showing an error message upon submission in Angular 4 according to the server's response

Struggling for hours to display an error message when a form submits and returns an error status code. The solution seems elusive... In the login form component below, I've indicated where I would like to indicate whether the form is valid or invalid ...

Difficulty with setting up a basic Angular 5 environment

I am facing difficulties in setting up and running Angular5 on my system. Here are the steps I followed in my home directory: $ sudo npm install @angular/cli -g $ ng new my-verbsandvocab $ cd my-verbsandvocab $ ng serve However, I encountered an erro ...

Defining optional parameters in TypeScript

Currently, I am working on implementing strong typing for a flux framework (specifically Vuex). Here is my current code: const actions = { first(context: Context, payload: string) { return doSomething(context, payload); }, second(context: Context) { r ...

I am unable to utilize the outcome of a custom hook within a function or within an effect hook

I've developed a unique custom hook that retrieves a list of individuals File: persons.hooks.ts import {useEffect, useState} from "react"; import Person from "../../models/person/Person"; const usePersons = () => { const ...

What is the best way to get my Discord bot to respond in "Embed" format using TypeScript?

I've been attempting to create a bot that responds with an embedded message when mentioned, but I'm running into some issues. Whenever I run this code snippet, it throws an error in my terminal and doesn't seem to do anything: client.on(&apo ...

Exploring the process of dynamically incorporating headers into requests within react-admin

Currently utilizing react-admin with a data provider of simpleRestProvider. I am in need of a solution to dynamically add headers to requests based on user interactions. Is there a way to achieve this? Appreciate any assistance. Thank you! ...