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

Sending detailed exception information from asp.net core to the client (such as Angular)

Trying to retrieve exception text from the backend (ASP.NET Core) in an Angular application has been a challenge. Examples have shown the controller action's return type as either JsonResult or ActionResult. In such cases, we can utilize the followi ...

Display options based on the value selected in the preceding selection

How can I dynamically display select options in an Angular select based on a previously selected value? Take a look at the code snippet below. Here, I have implemented a conditional display of select options (Target 1/Target 2) based on the value selected ...

In need of secure HTML, received a dose of Style instead

I am currently developing a component that loads html content dynamically and validates the loaded styles to prevent any mixing of app styles with the dynamic template's styles. This is the structure of my HTML component: <div class="modal-header ...

Tips for sending an Angular http post request including both data and an image:

When making a post request in Angular, I typically send data (such as 'product' data) using an object like this: product: any = {}; // filled with properties (code, barcode, name, description...) and then include it in the request: return this.h ...

Ditch the if-else ladder approach and instead, opt for implementing a strategic design

I am currently working on implementing a strategic design pattern. Here is a simple if-else ladder that I have: if(dataKeyinresponse === 'year') { bsd = new Date(moment(new Date(item['key'])).startOf('year&apos ...

Error: Platform core encountered a StaticInjectorError[t]: It is not possible to assign a value to the property '_injector', as it is undefined

This source code includes a rest API call and global variable reference. I have only utilized bootstrap CSS and omitted saving jQuery because bootstrap.js is not being used. After performing the (ng build -prod) command, I receive production build files ...

Can we replace node_module imports with a different module (e.g. swapping lodash with lodash-es)?

Currently in the process of upgrading from angular 9 to angular 10 within my mono-repo. Encountering numerous warnings like the ones below: WARNING in \libs\global-search\src\lib\components\status\status.component.ts depe ...

Theme not being rendered properly following the generation of a dynamic component in Angular

I am currently working on an Angular 9 application and I have successfully implemented a print functionality by creating components dynamically. However, I have encountered an issue where the CSS properties defined in the print-report.component.scss file a ...

Utilize TypeScript Compiler (tsc) without the need for global installation via

Currently, I am tackling a project that needs to be delivered to a group of individuals. This project is written in TypeScript, requiring them to execute the command tsc for compilation. The issue arises when I run this command following the execution of ...

Challenges arise with dependencies during the installation of MUI

[insert image description here][1] I attempted to add mui styles and other components to my local machine, but encountered a dependency error. How can I resolve this issue? [1]: https://i.stack.imgur.com/gqxtS.png npm install @mui/styles npm ERR! code ERE ...

Error encountered within eot file using file-loader and webpack

I am facing an issue while trying to integrate React Rainbow Components with Next.js (TypeScript). I encountered a problem with importing fonts, which led me to use webpack along with the url-loader. However, despite my efforts, I keep encountering the er ...

Exploring the Worldwide Influence of TypeScript, React, and Material-UI

I am currently following an official tutorial on creating a global theme for my app. In my root component, I am setting up the global theme like this: const themeInstance = { backgroundColor: 'cadetblue' } render ( <ThemeProvider theme ...

How to check Internet upload speed in Angular without using a backend server?

I need help uploading a file to a folder within my Angular app's directory while it is running on localhost. I have been unable to find a solution that doesn't involve using backend technologies. For instance, I simply want to upload an image fi ...

Display the initial occurrence from the *ngIf statement

Is there a way to display only the first match from the *ngIf? I am currently using an object loop with *ngFor, where I have multiple items with the same Id but different dates. I need to filter and display only the item with the most recent date and avo ...

Encountered an issue when trying to deserialize the current JSON object while submitting relational data

I have encountered a problem while trying to add a worker to a job, specifically when dealing with the ModelState check. Here are the steps I've taken: Filling out the form Upon submitting the form, I checked the console and found: Name = "test", ...

Unable to bind click eventListener to dynamic HTML in Angular 12 module

I am facing an issue with click binding on dynamic HTML. I attempted using the setTimeout function, but the click event is not binding to the button. Additionally, I tried using template reference on the button and obtaining the value with @ViewChildren, h ...

Tips for incorporating auth0 into a vue application with typescript

Being a beginner in TypeScript, I've successfully integrated Auth0 with JavaScript thanks to their provided sample code. However, I'm struggling to find any sample applications for using Vue with TypeScript. Any recommendations or resources would ...

Is there a way for me to access and install the Angular 2 release candidate through either npm or

When attempting to download Angular2 from npm or jspm, I am encountering an issue. Instead of getting the version 2.0.0-rc.1, I am receiving angular@^2.0.0-beta.17. Could this discrepancy be related to changes in the release candidate or it is a matter of ...

What steps should I take in order to correctly implement the onChange event and retrieve the event.target.value in my

Incorporating useForm, yupResolver, and Yup for validation caused issues with the previously functioning handleChange function. The value variable doesn't log anything when console.logged, indicating a disconnect with the input field content. Addition ...

Previous states in TypeScript

Just starting out with typescript and trying to work with user files in order to update the state. Currently facing a typescript error that I can't seem to figure out - Error message: Argument of type '(prev: never[]) => any[]' is not as ...