Angular - Scroll to the bottom of an element - html

So I have this 'output' element which fills up with messages, the overflow is set on scroll so after a certain amount of messages this element becomes scrollable. It doesn't auto scroll to the bottom though, so I tried doing this using the DOM, document.getElementById('output'), this didn't work and after some reading I learned this should be avoided in angular.
So I want to target this #output element in my output-window component with my typescript and access some scrollTo() method to scroll it to the bottom, how should I do this?
output-window.component.html:
<div id="output">
<p *ngFor="let message of messages">
{{ message }}
</p>
</div>
Project structure
home.component
+-->output-window.component
+-->div#output
Targeting this div#output is what's giving me trouble.

retrieve p tags with view children
#ViewChildren("p") ps: QueryList<any>
ngAfterViewInit() {
this.ps.last.nativeElement.scrollIntoView();
}
then access to native element and then scroll to it.
or better approach is write a directive for p element and set it for last element
Edit : It seems you need to name your p element like below
<div id="output">
<p *ngFor="let message of messages" #p>
{{ message }}
</p>
</div>
in order to make ViewChildren work properly.

I have created a stack blitz for you. Please check here

Related

Dynamically change the style of an undeclared html child component in Angular

I'm trying to dynamically change the style of an undeclared div. I'm using Angular and PrimeNG, and it's creating divs that I'm having trouble accessing through inline styles. The goal is to have a user input a width as a string (500px, 30rem, etc) and that width be text interpolated into those invisible divs.
Here is my HTML
<p-card>
<div class="wrapper">
<div class="percent basin-color-info">
<h2>{{ percentage }}%</h2>
</div>
<div class="info">
<h4>Percentage of time when outstanding risks are received</h4>
</div>
<div class="break"><hr /></div>
<div class="days">
<h5>{{ days }} Days</h5>
</div>
<div class="text"><h4>on average to correct outstanding risks</h4></div>
</div>
</p-card>
If I use inspector, it shows the following layout:
<p-card> (This is in the HTML)
<div class="p-card"> (This is **not** in the HTML)
<div> (This is **not** in the HTML)
<div> (This is **not** in the HTML)
<div class="wrapper"> (This is in the HTML)
...
</div>
</div>
</div>
</div>
</p-card>
I know that if I change the width of the first undeclared div with the p-card class in the inspector, the card changes how I'd like it to.
My hope is that I can use text interpolation {{ 500px }} or some sort of CSS injection to change the style of the undeclared divs, or some other workaround..
The p-card element from primeNG documentation says inline styles are an acceptable attribute but for some reason it doesn't change.
Hello Vincent Thomason,
From what I Understood, you are trying to style the div that is nested inside the p-card, that you don't have access to in your component HTML.
The only solution that I see is to give your p-card an id. Then use that id in querySelector and select the div inside ('myCardId>.p-card').
Here is a working stackblitz with what you want to accomplish:
https://stackblitz.com/edit/angular-ivy-nxjpwe?file=src/app/app.component.ts

Making Loading div accessible when the div is created

This container is created on the fly and added into the dom. The container is removed from the dom once the data is loaded. When this container is added into the dom and narrator/NVDA is on, I need to announce "Loading"
<div id="loadingContainer">
<span id="spinner">
<svg/>
</span>
<div id="loadingText" aria-label="Loading...">Loading...</div>
</div>
Tried role = "alert" for the loadingtext div but it announces "alert" which is not good for me. Tried role = "status" but it didnt announce anything, I presume because the container is created with the role attribute and there is no change in the value of the element.
Should be a simple matter of having a container for the container that's added with aria-live="polite". I always use polite for aria-live regions unless it's absolutely necessary for a message to be announced immediately, which is rarely needed.
So your code would just have
<div aria-live="polite">
<!-- your newly created <div> will go here -->
</div>
And when the container is created, you'd have:
<div aria-live="polite">
<div id="loadingContainer">
<span id="spinner">
<svg/>
</span>
<div id="loadingText" aria-label="Loading...">Loading...</div>
</div>
</div>
You'd also have to change the value of aria-relevant since the default is "additions text" which will only announce when you add the DOM element. If you want an announcement made when you remove that DOM element, you'd need "removals" too. Or simply use "all".
<div aria-live="polite" aria-relevant="all">
<!-- your newly created <div> will go here -->
</div>
role=“status” would be most suited for conveying the text. Alternatively you can choose to have no role but add an “aria-live=“assertive”. Be sure that the container with role=“status”/aria-live is present from the start, when the page is loaded, and then give it some content when you would like it to be announced. You should do this, because Firefox + NVDA screen-reader does not immediately see when a new live area appears in the DOM. Having it present from the start is the surefire way to let the browser + screen-reader listen for changes in that element.
You can also consider setting aria-busy=“true” on the actual element being updated.
Also, having an aria-label with the same text as it’s content (“Loading…”) won’t have any effect. Just skip the label and keep the text.

Angular: How can I remove wrapper (parent element) without removing the child?

I have seen this answer but it answers for jquery and not angular/typescript.
My question is similar to this question, but my question is seeking a solution for angular.
How can I remove wrapper (parent element) without removing the child in Angular using typescript or scss? (If it is possible by both kindly show both methods).
For example how to programatically manupulate the dom below from
<div class="wrapper">
<span>This is It!</span>
</div>
<div class="button">Remove wrapper</div>
to: (After clicking on the button I would like to have the dom iook like below)
<span>This is It!</span>
<div class="button">Remove wrapper</div>
EDIT:
Kindly also show how to set it so that it can add the wrapper div back when I click the button again. Basically toggling the wrapper div.
I think you can simulate using ng-template and two divs, some like
<div *ngIf="toogle" class="wrapper">
<ng-content *ngTemplateOutlet="template"></ng-content>
</div>
<ng-content *ngTemplateOutlet="!toogle?template:null"></ng-content>
<ng-template #template>
<hello name="{{ name }}"></hello>
</ng-template>
<button (click)="toogle=!toogle">toogle</button>
See a example in stackblitz

Angular 2 navigate to element in *ngFor using interpolation

I am using Angular 2 and looking to set-up a page where the contents are displayed through an *ngFor loop, and the body is displayed through a separate div. These use interpolation to display the objects relevant properties. I would like the content to link to the relevant div in the body.
To display the contents in the left hand side:
<div class = "contents">
<div *ngFor = "let disp of content">
{{disp.heading}}
</div>
</div>
To display the article on the right hand side
<div *ngFor="let disp of content>
{{disp.header}}
{{disp.body}}
<div>
This is similar to the query here Angular2 Routing with Hashtag to page anchor
However, as it is in an *ngFor loop dependent on content, abd uses interpolation, I cannot see a way to identify different divs within the loops as these are provided dynamically.
However, as it is in an *ngFor loop dependent on content
Not necessarily, You can get the current index of a *ngFor in angular using the predefined index variable
So, we can set the links to point to href=#content{{i}} which is href=#content0 for the first element, href=#content1 for the second element and so on,
<div *ngFor="let disp of content; let i=index">
{{disp.heading}}
</div>
Then we can create the content divs using the same idea,
<div *ngFor="let disp of content; let i=index" id="content{{i}}">
<h1> {{disp.header}} </h1>
<p> {{disp.body}} </p>
</div>
so the first div will have an id #content0, the second one #content1 and so on,
working example
Hope this helps

hrefs with anchor scroll inside a dropdown

I have a drop-down like so:
<div class="dropdown">
<select>
<option ng-repeat="i in sc.cl" value="{{i.deptname"}}><a ng-href="#{{i.id}}">{{i.deptname}}</a></option>
</select>
</div>
Basically, the dropdown element's name is inside an array and there are divs inside the html having the id as i.id like this:
<div class="right-bar">
<section class="contact-block" ng-repeat="i in sc.cl" id="{{i.id}}">
<div class="description">{{i.deptname}}</div>
<div class="inner-block">
<div ng-repeat="j in i.cgs">
<img class="vertical-image" src="frame.png">
<img class="horizontal-image" src="mobileframe.png">
</div>
</div>
</section>
</div>
whenever I click the dropdown element, I want it to scroll to the particular section. But nothing happens when I do so. Why does this happen? And when I tried inspect element in chrome, it doesn't even show the tags in the ng-repeat dropdown.
You should use Angular's $anchorScroll.
Please, take a look at this similar question: How to handle anchor hash linking in AngularJS
Uhhm, my suggestion seems completely unrelated as I'm a dummy at AngularJS. But I have a solution to scrolling to a section using jQuery. You could simply give the section an ID and animate scrolling to that point on click by calculating the top offset and animating the scrolltop to that point...If you want me to show you the code, I'll gladly do so...:-) (Oh and I know this should be a comment because it doesn't directly answer the question, but my reputation's 13 so I can't comment)...