In the latest version of Angular, accessing document.getelementbyid consistently returns null

I am struggling with a component that looks like this

export class NotificationPostComponent extends PostComponent implements OnInit, AfterViewInit {
    commentsDto: IComment[] = [];
    commentId = '';
    ngOnInit(): void {
    this.route.data.subscribe(data=>{
      this.post = data.post;
    });
    this.route.params.subscribe((param : Params) => {
      const slug = param['slug'];      
      this.commentId = param['commentid'];
      this.notifiService.loadCommentsOfPost(slug, this.commentId).subscribe(data=>{
          this.commentsDto = data.comments;       
        })       
    });
    super.ngOnInit();    
  }
  ngAfterViewInit(): void {
    var idDiv = document.getElementById(this.commentId)
    console.log(idDiv)
  }
}

I have an HTML element with ID as Guid:

<div id="{{cmt.id}}" *ngFor="let cmt of commentsDto">
  <div>comment</div>
</div>

The issue arises when the document.getElementById always returns null after view initialization. Can someone please point out where I might have made a mistake?

Answer №1

<!--refer to the template variable "#comment"-->
<div #comment id="{{cmt.id}}" *ngFor="let cmt of commentsDto">
  <div>comment</div>
</div>

//The comments are stored in a QueryList (similar to an array)
@ViewChildren('comment') comments:QueryList<ElementRef>

this.notifiService.loadCommentsOfPost(slug, this.commentId).subscribe(data=>{
      this.commentsDto = data.comments;       
      //Wait for Angular to render the elements
      setTimeout(()=>{
        const comment=this.comments
            .find(x=>x.nativeElement.getAttribute('id')==myId)
        if (comment)
            comment.nativeElement.scrollIntoView(
              {Behavior:"Smooth",Block:Start,inline:"Nearest"})
       })
    })  

You can use "nativeElement.getAttribute" or find the index of the comment and get the element at that index, something like:

        const index=this.commentsDto.findIndex(x=>x.id==myInd)
        const comment=this.comments
            .find((_,i)=>i==index)

Answer №2

Angular provides a convenient alternative to document.getElementById through its built-in API: @ViewChildren.

To improve organization, consider extracting the inline template into a new component.

Template

<button (click)="scrollToBottom()">Scroll to last comment</button>

<app-comment [title]="comment.title" *ngFor="let comment of comments$ | async">
</app-comment>

<button (click)="scrollToTop()">Scroll to 1st Comment</button>

Utilize ViewChildren in the Component to access the collection of CommentComponents represented by a QueryList.

If direct access to HTML elements is needed, configure @ViewChildren to read the ElementRef (

@ViewChildren(CommentComponent, { read: ElementRef })
).

Component

export class NotificationPostComponent extends PostComponent
  implements OnInit, AfterViewInit {
    comments$ = /* Stream of Comments */

    @ViewChildren(CommentComponent, { read: ElementRef })
  commentElementReferences: QueryList<ElementRef<HTMLElement>> | undefined;
}

You can mark each Comment Component with an attr-Binding for identification if scrolling to a specific element is required.

Template

<app-comment
  [title]="comment.title"
  [attr.data-anchor]="comment.id"
  *ngFor="let comment of comments$ | async"
>
</app-comment>

Add logic to your component to find and scroll to the desired Element based on ID or other attributes.

Component

private scrollToCommentById(id: string) {
    if (!this.commentElementReferences) return;

    const commentToScrollTo = this.commentElementReferences
      .map((reference) => reference.nativeElement)
      .find((element) => element.getAttribute('data-anchor') === id);

    commentToScrollTo.scrollIntoView({ behavior: 'smooth' });
  }

Trigger the scrolling mechanism upon navigation by connecting to the activated route.

  ngAfterViewInit(): void {
    // Listen to parameter changes in route
    this.activatedRoute.paramMap
      .pipe(
        map((paramMap) => paramMap.get('id')),
        filter((id) => !!id),
        tap((id) => this.scrollToCommentById(id))
      )
      .subscribe();
  }

Demo

Explore this StackBlitz @ViewChild Demo showcasing the setup, including the button that scrolls to a specific Comment by its ID.

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

ReactJS Provider not passing props to Consumer resulting in undefined value upon access

Hey there! I've been facing an issue with passing context from a Provider to a consumer in my application. Everything was working fine until suddenly it stopped. Let me walk you through a sample of my code. First off, I have a file named AppContext.t ...

sort the array based on its data type

Recently diving into typescript... I have an array that is a union of typeA[] | typeB[] but I am looking to filter based on the object's type interface TypeA { attribute1: string attribute2: string } interface TypeB { attribute3: string attri ...

Issue with React filter function where data is not being displayed when search query is left

I am facing an issue where the data does not show up when the search term is empty. Previously, I used to have this line in my code if (!searchTerm) return data for my old JSON data, and it worked fine. However, now that I'm using Sanity CDN, this lo ...

Set the value of HTML input type radio to a nested JSON string

Currently, I'm developing an Angular application and encountering an issue where I am unable to access the nested array value 'subOption.name' for the input type radio's value. I'm uncertain if the error lies within the metaData st ...

Having difficulty subscribing to multiple observables simultaneously using withLatestFrom

I am facing an issue where I have three observables and need to pass their values to a service as parameters. I attempted to do this using WithLatestFrom(), but it works fine only when all values are observables. this.payment$.pipe( withLatestFrom(this.fir ...

What is the process for configuring React on one server and springboot on a separate server?

Can you help me with the setup of the following: Web Server : I need to set up a react + typescript application using npm at Backend Server : I also need to configure a Springboot backend server at I am currently using webpack to build the react applica ...

Next.js components do not alter the attributes of the div element

I am encountering a problem with nextjs/reactjs. I have two tsx files: index.tsx and customAlert.tsx. The issue that I am facing is that the alert does not change color even though the CSS classes are being added to the alert HTML element. Tailwind is my c ...

tips for incorporating datatable into ng bootstrap modal within an angular application

I am trying to create a data table within an ng-bootstrap modal in Angular using Bootstrap and the angular-data tables module. My goal is to display the data table specifically within a bootstrap modal. ...

Encountering a Javascript error while trying to optimize bundling operations

After bundling my JavaScript with the .net setting BundleTable.EnableOptimizations = true;, I've encountered a peculiar issue. Here's the snippet of the generated code causing the error (simplified): var somVar = new b({ searchUrl: "/so ...

Access to Firebase using Google authentication is currently restricted (permission denied)

Currently, I am utilizing Firebase to authenticate users with Google in my Angular project, "project1." When signing anonymously into Firebase, everything runs smoothly. However, if I attempt to sign in with Google using the popup feature, an error occurs: ...

Transforming JSON in Node.js based on JSON key

I am having trouble transforming the JSON result below into a filtered format. const result = [ { id: 'e7a51e2a-384c-41ea-960c-bcd00c797629', type: 'Interstitial (320x480)', country: 'ABC', enabled: true, ...

The Angular CLI suddenly decided to stop providing me with useful lines (without sourcemaps) in the browser console, but interestingly the terminal continues

I recently noticed a change in my Angular project that is using Angular CLI. Instead of receiving error lines from my code, I am getting errors from compiled files like main.js and vendor.js. The 'normal' error messages in my terminal are pointin ...

How to Incorporate and Utilize Untyped Leaflet JavaScript Plugin with TypeScript 2 in Angular 2 Application

I have successfully integrated the LeafletJS library into my Angular 2 application by including the type definition (leaflet.d.ts) and the leaflet node module. However, I am facing an issue while trying to import a plugin for the Leaflet library called "le ...

What is the best way to convert an array of data into a dataset format in React Native?

Within my specific use case, I am seeking to reform the array structure prior to loading it into a line chart. In this context, the props received are as follows: const data = [26.727, 26.952, 12.132, 25.933, 12.151, 28.492, 12.134, 26.191] The objective ...

How can the spacing between Angular Material's mat-card-content and mat-card-actions be adjusted?

I am creating a mat card layout where there are two separate cards within the main card's content section. However, when I add a button for the actions section of the main card, there is no spacing between these two sections. How can I create a vertic ...

RxJS pipe operation ignoring observable

Currently, I am in the process of transitioning an app from Promises to RxJS and I could use some guidance on whether I am heading in the right direction. Situation: I have a ModalComponent that appears when an HTTP request is sent and disappears once the ...

Does this fall under the category of accepted practices for employing an effect in Angular?

I am working on integrating an Angular directive with a signal that receives values from a store selector. This signal is crucial for determining whether a button should be disabled or not. I'm curious about the best approach to listen to this signal ...

Is it possible to merge these two scripts into a single one within Vue?

As a newcomer to VUE, I am faced with the task of modifying some existing code. Here is my dilemma: Within a single component, there are two script tags present. One of them contains an import for useStore from the vuex library. The other script tag incl ...

The argument provided needs to be a function, but instead, an object instance was received, not the original argument as expected

I originally had the following code: const util = require('util'); const exec = util.promisify(require('child_process').exec); But then I tried to refactor it like this: import * as exec from 'child_process'; const execPromis ...

Could you please explain the significance of /** @docs-private */ in Angular's TypeScript codebase?

After browsing through the @angular/cdk code on GitHub, I came across a puzzling "docs-private" comment. Can anyone explain its significance to me? Link to Code * In this base class for CdkHeaderRowDef and CdkRowDef, the columns inputs are checked for ...