I have a list where each li has unique data-id.
<ul class="list">
<li class="list__el"
*ngFor="let item of cars"
data-id="{{ item.id }}">
</li>
</ul>
In JS I would wrote
let myLi = document.querySelector(`.list__el[data-id="${item.id}"]`)
How to correctly rewrite it for Angular?
Use #ViewChildren and a template reference such as #listItem.
#Component({
template: `<ul class="list">
<li #listItem class="list__el"
*ngFor="let item of cars"
data-id="{{ item.id }}">
</li>
</ul>`
})
export component MyComponent implements AfterViewInit {
// Note that the parameter here relates to the #listItem in the template.
#ViewChildren('listItem')
public listItems!: QueryList<ElementRef<HTMLLIElement>>
public ngAfterViewInit() {
console.log(
this.listItems.find(itm =>
itm.nativeElement.getAttribute('data-id') === 'my-element-id'
)
)
}
}
Related
I fetch data from api by resolver before loading component, also can see whole data in console and {{ data.length }} prints correct 100 number as well, but ngFor renders random amount of data about 20
// data.component.ts
data: BooksData[];
ngOnInit(): void{
this.route.data.subscribe(
data => {
console.log(data) // prints entire data correctly, data: Array(100)
this.data = data;
}
)
}
{{ data.length }} <!-- 100 -->
<ul>
<li *ngFor="let d of data">{{ d.title }}</li>
</ul>
i also tried slice pipe *ngFor="let d of data | slice:0:(data.length-1)" but same result
You have syntax problem in the interpolation of data.title
{{ data.length }} <!-- 100 -->
<ul>
<li *ngFor="let d of data">{{ data.title }}</li>
</ul>
Should be
{{ data.length }} <!-- 100 -->
<ul>
<li *ngFor="let d of data">{{ d.title }}</li>
</ul>
Syntax issue data.title should be d.title
.html:
<ul>
<li *ngFor="let d of data | async">{{ d.title }}</li>
</ul>
You already know now what is the problem from above comments.
i.e data.tile need to changed to d.title
If you want you can use below more readable code
books$: BooksData[];
ngOnInit(): void{
this.books$ = this.route.data;
}
In html
<ul *ngIf="books$ | async as books">
<li *ngFor="let book of books">
{{ book.title }}
</li>
</ul>
I'd be a happy man if someone could explain why the following is not working as expected please?
The hasCreative is a boolean but regardless of its true/false value, the <li> is always displayed. Any suggestions would be great. Thank you.
<ng-container *ngIf="uiModel$ | async as model">
<ul class="nav" style="padding-bottom: 30px;">
<li *ngIf="model.hasCreative" class="nav-item">
<a class="nav-link active" routerLinkActive="active" [routerLink]="['']">Home</a>
</li>
</ul>
</ng-container>
export class UserInterfaceModel {
hasCreative: boolean;
}
#Injectable({
providedIn: 'root'
})
export class UserInterfaceService {
user: CognitoUser;
userLoggedIn = false;
private userInterfaceModelSubject$: Subject<UserInterfaceModel> = new Subject();
userInterfaceModel$ = this.userInterfaceModelSubject$.asObservable();
constructor(private authService: AuthService) {
combineLatest([this.authService.onUserLoaded$]).subscribe(([currentUser]) => {
this.user = currentUser;
this.userLoggedIn = true;
this.buildUserInterfaceModel();
});
}
buildUserInterfaceModel(){
const model = new UserInterfaceModel();
if (this.userLoggedIn && this.user !== null){
model.hasCreative = this.user.getSignInUserSession().getIdToken().payload.creative;
}
this.userInterfaceModelSubject$.next(model);
}
}
Try using this:
<ng-container *ngIf="uiModel$ | async as model; else loading">
<ul class="nav" style="padding-bottom: 30px;">
<li *ngIf="model.hasCreative === true " class="nav-item">
<a class="nav-link active" routerLinkActive="active" [routerLink]="['']">Home</a>
</li>
</ul>
</ng-container>
<ng-template #loading>
Loading stuff...
</ng-template>
If loading template will render it means your Observable has no value. If it dosnt work too, try render the value of model.hasCreative by adding somethin like this:
<span>{{model.hasCreative}}<span>
out of <ul> tag to see if model.hasCreative has true/false value or not.
I have an array of items and I want to apply style class to an element which has my customname.
The style is not applying for any element. How can apply style based on condition?
var items =["one","two","three"];
<li repeat.for="item of items" class="${item == 'one'? 'someclass':''}">${item}</li>
Here's an example: https://gist.run?id=ed73adef9c634efbfc4dd109a68ec2c2
app.html
<template>
<h1>${message}</h1>
<ul ref="ul">
<li repeat.for="item of items" class="${item == 'one' ? 'someclass' : ''}">
${item}
</li>
</ul>
<h4>Resulting HTML:</h4>
<pre><code>${debug}</code></pre>
</template>
app.js
export class App {
message = 'Hello World!';
items = ["one","two","three"];
get debug() {
return this.ul.outerHTML;
}
}
Let's say I have an unordered list like so
<div>
<ul class="data-container">
<li #H1>00</li>
<li #H2>01</li>
<li #H3>02</li>
<li #H4>03</li>
<li #H5>04</li>
...
</ul>
</div>
What's the best way to get a element based on it's local variable using ViewChild then retrieving it's value and give it a special class (say class="active")
Is there a filter or find function I can use here?
Also, let's say I want to select one of the items, is there a better way than using (click)="SelectElement()" on all of them?
You can create a LiDirective to mark all LI. After that you can use all API provided my QueryList like find,filter, reduce, toArray ...
#Directive({
selector:'li'
})
export class LiDirective{}
#Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<div>
<ul class="data-container">
<li>00</li>
<li #H2>01</li>
<li #H3>02</li>
<li #H4>03</li>
<li #H5>04</li>
</ul>
</div>
</div>
`,
})
export class App {
#ViewChildren(LiDirective, {read:ElementRef}) lis: QueryList<any>;
name:string;
constructor(private renderer: Renderer2) {
this.name = `Angular! v${VERSION.full}`
}
ngAfterViewInit() {
let second = this.lis.toArray()[2];
this.renderer.setStyle(second.nativeElement, 'color', 'blue');
}
}
How to send item from v-for to slot? In vue.js.
ListComponent:
<ul>
<li v-for="item in list">
<slot></slot>
</li>
</ul>
Page view:
<list-component :list="list">
<span v-text="item.value"></span>
</list-component>
Code <span v-text="item.value"></span> can't access item (from component's scope). Is it a way to send an item from component to code in tag?
P.S. I know, that as a workaround I can send $index from component to parent view, but it's a little bit hacky
UPD: Example of my current workaround (somebody may find this useful):
Declare index in view's data:
data () {
return {
index: 0,
list: [ ... ]
}
Add to index param to the view's template:
<list-component :list="list" :index="index">
<span v-text="list[index].value"></span>
</list-component>
Declare index in component's props:
props: {
index: {
type: Number
}
}
Add index to v-for's element:
<ul>
<li v-for="item in list" index="$index">
<slot></slot>
</li>
</ul>
the bind expression is compiled in the context who define them,so:
v-text="item.value"
can not be compiled because in Page view there is no "item" defined.
maybe you can try to change your code structure like below:
ListComponent:
//content in component
<span>i am text in component,item value is:{{item.value}}</span>
<slot></slot>
Page view:
<ul>
<li v-for="item in list">
<list-component :item="item"></list-component>
</li>
</ul>