我创建了一个可重用组件(星级评定),我计划在多个地方使用它来对不同的事物进行评分,当我仅使用可重用组件一次时它工作正常,但当我在组件上多次使用它时它不会被渲染。
正如您可能已经猜到的,可重用组件(星级评定组件)具有星星,当
@input
属性具有某些值时,这些星星将突出显示,例如,如果 @input
属性具有 3,则将突出显示 3 颗星,如果为 4,则突出显示 4 颗星。
当我在多次使用可重用组件(星级组件)的地方使用它时,如果仅最后考虑
@input
属性,并且不同组件具有不同的值。
我做了一个迷你演示,并粘贴了代码来理解
评级.component.html
<div class="rating-wrapper">
<!-- star 5 -->
<input type="radio" id="5-star-rating" name="star-rating" value="5" [checked]="starrating === '5'" (change)="onRatingChange($event.target)" [(ngModel)]="starrating">
<label for="5-star-rating" class="star-rating">
<i class="fa fa-star d-inline-block"></i>
</label>
<!-- star 4 -->
<input type="radio" id="4-star-rating" name="star-rating" value="4" [checked]="starrating === '4'" (change)="onRatingChange($event.target)" [(ngModel)]="starrating" >
<label for="4-star-rating" class="star-rating star">
<i class="fa fa-star d-inline-block"></i>
</label>
<!-- star 3 -->
<input type="radio" id="3-star-rating" name="star-rating" value="3" [checked]="starrating === '3'" (change)="onRatingChange($event.target)" [(ngModel)]="starrating">
<label for="3-star-rating" class="star-rating star">
<i class="fa fa-star d-inline-block"></i>
</label>
<!-- star 2 -->
<input type="radio" id="2-star-rating" name="star-rating" value="2" [checked]="starrating === '2'" (change)="onRatingChange($event.target)" [(ngModel)]="starrating">
<label for="2-star-rating" class="star-rating star">
<i class="fa fa-star d-inline-block"></i>
</label>
<!-- star 1 -->
<input type="radio" id="1-star-rating" name="star-rating" value="1" [checked]="starrating === '1'" (change)="onRatingChange($event.target)" [(ngModel)]="starrating">
<label for="1-star-rating" class="star-rating star">
<i class="fa fa-star d-inline-block"></i>
</label>
</div>
评级.组件.css
.container-wrapper {
background-color: #EDF0F9;
}
.container {
height: 100vh;
}
.rating-wrapper {
align-self: center;
/* box-shadow: 7px 7px 25px rgba(198, 206, 237, 0.7), -7px -7px 35px rgba(255, 255, 255, 0.7), inset 0px 0px 4px rgba(255, 255, 255, 0.9), inset 7px 7px 15px rgba(198, 206, 237, 0.8); */
border-radius: 4rem;
display: inline-flex;
direction: rtl !important;
padding: 1.5rem 2.5rem;
margin-left: auto;
}
.rating-wrapper label {
color: #E1E6F6;
cursor: pointer;
display: inline-flex;
font-size: 2.1rem;
padding: 1rem 0.6rem;
transition: color 0.5s;
}
.rating-wrapper svg {
-webkit-text-fill-color: transparent;
-webkit-filter: drop-shadow 4px 1px 6px #c6ceed;
filter: drop-shadow(5px 1px 3px #c6ceed);
}
.rating-wrapper input {
height: 100%;
width: 100%;
}
.rating-wrapper input {
display: none;
}
.rating-wrapper label:hover,
.rating-wrapper label:hover ~ label,
.rating-wrapper input:checked ~ label {
color: #34AC9E;
}
.rating-wrapper label:hover,
.rating-wrapper label:hover ~ label,
.rating-wrapper input:checked ~ label {
color: #34AC9E;
}
评级.组件.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-rating',
templateUrl: './rating.component.html',
styleUrls: ['./rating.component.css']
})
export class RatingComponent {
constructor(){}
@Input() starrating:string='3'; //<== this will get value and the stars will be highlighted
onRatingChange(val:any){
//blah blah blah
}
}
当我在其他组件中使用它时,它不会被渲染
Manytimes.Component.html
<div *ngFor="let item of arrayResponse">
<img
src="assets\150.png"
class="img-fluid rounded-circle mb-3"
alt="coach image"
/> <br>
<div>{{item.name}}</div>
<app-rating [starrating]="item?.rating"></app-rating> // here I am passing the value of how many star should get highlighted
</div>
Manytimes.Component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-manytimes',
templateUrl: './manytimes.component.html',
styleUrls: ['./manytimes.component.css']
})
export class ManytimesComponent {
// just for demo the below response is hard coded, but actually it will come from api response
arrayResponse:any=[
{
"name":"ram",
"rating":"3"
},
{
"name":"Dinesh",
"rating":"1"
},
{
"name":"ganesh",
"rating":"2"
},
]
}
当在我的应用程序中渲染时,我期望第一个应该突出显示 3 颗星,然后是 1 颗星,最后一个应该突出显示 2 星
但只有最后一个用 2 星突出显示,所有其他都是空白
为什么会发生这种情况?我读了很多其他答案,但无法使其发挥作用。有人可以帮忙吗? 谢谢
主要问题是
@Input() starrating:string='3';
改变了视图,因此指令 [(ngModel)]
获得了最后发出的值,即“2”。
这里,解决方案使用了一个附加标识符,稍后您将在子组件中使用它 - 评级。您可以通过多种方式执行此操作,例如,收集数组中的索引位置并将其传递为
<app-rating [componentId]="i"></app-rating>
<div *ngFor="let item of arrayResponse; let i = index">
<img src="assets\150.png" class="img-fluid rounded-circle mb-3" alt="coach image"/> <br>
<div>{{item.name}}</div>
<app-rating [starrating]="item?.rating" [componentId]="i"></app-rating>
</div>
更新的评级组件:
ngOnInit() {
this.selectedRating[this.componentId] = this.starrating;
}
@Input() starrating: any = '3';
@Input() componentId: number = 0;
selectedRating: { [componentId: string]: string } = {};
onRatingChange(componentId: number, rating: string) {
this.selectedRating[componentId] = rating;
}
在这里您可以注意到我们创建了一个新对象
selectedRating
,它保存临时数据。您实际上可以在父级创建此对象并将其作为附加输入传递给子组件,这样您就不会丢失新输入保存的数据,但是对于此示例,我们可以跳过此操作。
由于我们启动了一个新变量 -
@Input() componentId: number = 0;
和 selectedRating: { [componentId: string]: string } = {};
,我们需要在 rating.component.html
中使用它们:
<div class="rating-wrapper">
<ng-container *ngFor="let star of ['5', '4', '3', '2', '1']">
<input
type="radio"
[id]="star + '-star-rating-' + componentId"
[name]="componentId + '-star-rating'"
[value]="star"
[ngModel]="selectedRating[componentId]"
(change)="onRatingChange(componentId, star)"
/>
<label [for]="star + '-star-rating-' + componentId" class="star-rating">
<i class="fa fa-star d-inline-block"></i>
</label>
</ng-container>
</div>
我在这里:
name
,它为每个组件保存一个唯一的值。这是一种重要的方式,因为它确保恒星的一个组成部分的变化不会影响另一个组成部分。当您使用属性并且想要进行两种方式绑定时,您需要一种
@Input
和一种@Output
,请参阅docs - 请参阅“输出名称是属性+更改”
@Input() starrating!: number | string;
@Output() starratingChange = new EventEmitter<number|string>();
当您使用输入类型的收音机并且想要创建“收音机组”时,输入应该有一个“名称”。但这个属性对于“整个群体”来说应该是唯一的。您的组件始终具有相同的名称:
star-rating
您可以选择两个选项,使用外部变量或强制用户创建属性“名称”,请参阅this SO
let StarratingUniqueId = 0;
@Component({
...
}){
export class RatingComponent {
id:number;
constructor(){
this.id=StarratingUniqueId ++;
}
}
或者
constructor(@Optional() @Attribute('name') public name:string){
if (!name)
throw new Error("The name attribute it's neccessary")
}
除了使用checked之外,你还可以使用类似的东西
[class.checked]="starrating === '1'"
并使用
input.checked{...}
当您在表单内的多个 input 元素中使用相同的 name 属性值时,可能会导致意外行为,因为浏览器将这些输入视为同一组的一部分。这可能会导致表单提交和数据处理出现问题。当您对具有相同名称的多个输入使用 ngModel 绑定时,所有这些输入可能会绑定到组件中的相同属性。因此,一个输入的更改将立即反映在共享相同名称的所有其他输入中。
您可以在此处为 name 属性指定唯一值。
评级.component.html
<div class="rating-wrapper">
<!-- star 5 -->
<input
type="radio"
id="5-star-rating"
name="5-star-rating"
value="5"
[checked]="starrating === '5'"
[(ngModel)]="starrating"
/>
<label for="5-star-rating" class="star-rating">
<i class="fa fa-star d-inline-block"></i>
</label>
<!-- star 4 -->
<input
type="radio"
id="4-star-rating"
name="4-star-rating"
value="4"
[checked]="starrating === '4'"
[(ngModel)]="starrating"
/>
<label for="4-star-rating" class="star-rating star">
<i class="fa fa-star d-inline-block"></i>
</label>
<!-- star 3 -->
<input
type="radio"
id="3-star-rating"
name="3-star-rating"
value="3"
[checked]="starrating === '3'"
[(ngModel)]="starrating"
/>
<label for="3-star-rating" class="star-rating star">
<i class="fa fa-star d-inline-block"></i>
</label>
<!-- star 2 -->
<input
type="radio"
id="2-star-rating"
name="2-star-rating"
value="2"
[checked]="starrating === '2'"
[(ngModel)]="starrating"
/>
<label for="2-star-rating" class="star-rating star">
<i class="fa fa-star d-inline-block"></i>
</label>
<!-- star 1 -->
<input
type="radio"
id="1-star-rating"
name="1-star-rating"
value="1"
[checked]="starrating === '1'"
[(ngModel)]="starrating"
/>
<label for="1-star-rating" class="star-rating star">
<i class="fa fa-star d-inline-block"></i>
</label>
</div>
我们还可以使用 Angular 的 ngFor 指令根据值数组动态生成星级输入来简化代码。
<div class="rating-wrapper">
<ng-container *ngFor="let rating of [5, 4, 3, 2, 1]">
<input
type="radio"
[id]="rating + '-star-rating'"
[name]="'star-rating-' + rating"
[value]="rating"
[checked]="starrating === rating.toString()"
/>
<label [for]="rating + '-star-rating'" class="star-rating">
<i class="fa fa-star d-inline-block"></i>
</label>
</ng-container>
</div>