#angular #typescript
Вопрос:
Компонент имеет входные данные от своего родителя и имеет выходное событие для этого входного объекта. ngStyle берет объект стиля из компонента для стилизации. Событие on click изменило логическое значение, но объект стиля не обновляется соответствующим образом, поэтому цвет остается неизменным. Я должен переназначить новый объект, чтобы ngStyle увидел новое логическое значение. Что я делаю не так?
ProductItemКомпонент.ts:
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import {Product} from '../../model/product';
@Component({
selector: 'app-product-item',
templateUrl: './product-item.component.html',
styleUrls: ['./product-item.component.css']
})
export class ProductItemComponent implements OnInit {
@Input() public product!:Product;
@Output() private updateStatus: EventEmitter<Product>;
public statusTextStyle:object;
public classStyle:object;
constructor() {
this.updateStatus = new EventEmitter<Product>();
}
ngOnInit(): void {
this.statusTextStyle = {
// if true color green, if false red
"color" : this.product.getStatus() ? "var(--ok)" : "var(--danger)"
}
}
onUpdateStatus(event){
this.updateStatus.emit(this.product);
// have to reassign a new object to change style
this.statusTextStyle = {
"color" : this.product.getStatus() ? "var(--ok)" : "var(--danger)"
}
console.log(this.statusTextStyle);
}
}
Product-item.component.html:
<div class="productContainer">
<div class="overlay">
<div [ngStyle]="statusTextStyle">{{product.name}}</div>
<hr>
<div>Status: {{product.getStatus()}}</div>
<div>Price: {{product.price}}</div>
<br>
<div>Code: {{product.code}}</div>
<br>
<div>Stock: {{product.quantity}}</div>
<hr>
<button (click)="onUpdateStatus($event)">UPDATE STATUS</button>
</div>
</div>
Родитель:
import { Component, OnInit } from '@angular/core';
import { Product as ProductModel} from '../../model/product';
@Component({
selector: 'app-product-list',
templateUrl: './product-list.component.html',
styleUrls: ['./product-list.component.css']
})
export class ProductListComponent implements OnInit {
products: Array<ProductModel>;
constructor() { }
ngOnInit(): void {
this.products = [
new ProductModel('A','1',3,40),
new ProductModel('B','2',4,50),
new ProductModel('C','3',22,41),
new ProductModel('E','4',342,433),
new ProductModel('Z','5',33,477)
]
}
onUpdateStatus(product:ProductModel){
product.setStatus(!product.getStatus());
console.log(product.getStatus());
}
}
Родительский html:
<div class="productList">
<div *ngFor="let product of products; let index as i;">
<app-product-item [product]="product" (updateStatus)="onUpdateStatus($event)"></app-product-item>
</div>
Модель продукта:
export class Product {
private _status:boolean = false;
constructor(public name:string,
public code:string,
public price:number,
public quantity:number){}
public getStatus():boolean{
return this._status;
}
public setStatus(status:boolean):void{
this._status = status;
}
}
если this.statusTextStyle
он не переназначен новым объектом (вспомните GetStatus()), стиль ngStyle использует стиль, установленный в ngOnInit
Комментарии:
1. Можете ли вы предоставить свой
ngStyle
код? Я думаю, ваша проблема в том, что вы должны назначитьthis.statusTextStyle.color = this.product.getStatus() ? "var(--ok)" : "var(--danger)"
. И тогда вам, вероятно, нужно позвонитьChangeDetectorRef
(ввести его)changeDetectorRef.detectChanges()
. Я не рекомендую этот подход из-за производительности, если вы можете предоставить больше кода, возможно, я смогу придумать что-то другое. 🙂2. почему вы ожидаете
product.getStatus()
вернуть что-то другое, когда в этом коде, похоже, ничего не меняется в объекте продукта? Вам также кажется, что вам не хватаетCommonModule
импорта на основе этого сообщения об ошибке? также вашаngStyle
привязка была бы полезна при задании вопроса обngStyle
использовании.3. @JorgeMussato Я инициализировал
this.statusTextStyle
новый объект вngOnInit
. Если я назначу, какthis.statusTextStyle.color
жалобы на ошибку: Цвет свойства не существует для типа «объект».4. @bryan60 Я только недавно взял Angular и следил за книгой
Angular Up and Running
. Компонентevent emitter
in вызовет событие этого вывода от своего родителя, если я правильно его понимаю. Значение действительно изменилось, как я показал в console.log5. можете ли вы создать минимальную демонстрационную версию stackblitz
Ответ №1:
@CloudWave, вам нужно инициализировать вывод: @Output() private updateStatus: EventEmitter<Product>=new EventEmitter<Product>();
Но если вы проверите свой код, убедитесь, что вы не меняете statusTextStyle
его ни в каком другом месте. ngOnInit происходит только тогда, когда компонент окрашивается в первый раз (или если у вас есть компонент под *ngFor и вы также меняете массив под *ngIf).
Вы можете проверить эту работу, если раскомментируете строки под своим //reassign object only works
.
Другой способ-сделать добытчика
get statusTextStyle(){
return {
color: this.product.getStatus() ? "var(--ok)" : "var(--danger)"
};
}
Ваш раздвоенный стекблитц с помощью геттера
ПРИМЕЧАНИЕ: Когда вы передаете объект на вход, вам не нужно передавать @Output
продукт, любые изменения в объекте-в дочернем или родительском — изменяют местоположение
Обновите хорошо, примечание неясно. Я хочу сказать, что когда вы используете как @Input
с объектом, объект всегда один и тот же. Вы можете изменить одно свойство объекта в любом месте-в родительском или дочернем, поэтому мы можем сделать это в дочернем
onUpdateStatus(event) {
this.product.setStatus(!this.product.getStatus());
}
Мы не меняем «продукт» в родительском, и нам не нужно использовать @Output.
Комментарии:
1. Я подумал, что если я инициализирую стиль в ngOnInit, то после этого стиль будет продолжать меняться. Значит, в строке используется геттер
<div [ngStyle]="statusTextStyle">{{product.name}}</div>
? Что это значитpass to the @Output the product
?2. «ngOnInit» не создает связь между переменными, получает фактические переменные и вычисляет остальные. По поводу
@Input
, я обновил ответ, чтобы четко указать примечание.3. Спасибо за ответ. Вообще-то я делаю упражнение. В книгах говорится, что для того, чтобы дочерний компонент был действительно повторно использован, объект данных должен передаваться его родительским компонентом, поэтому я использую
@Output
декоратор для обеспечения инкапсуляции.
Ответ №2:
Братан, я хочу добавить сюда свой фрагмент кода, и он отлично работает, может быть, это тебе поможет.
Style1={
fontSize: '3em',
backgroundColor: this.CardData > 1 || this._ProductQuantity > 1 ? 'ivory' : "orange",
color: this.CardData > 1 || this._ProductQuantity > 1 ? "green" : "red",
'fa': true,
'far fa-check-square': this.CardData > 1 || this._ProductQuantity > 1,
'far fa-times-circle': this.CardData < 1 || this._ProductQuantity < 1
};
Вместо использования «var(—ok)» я использую прямые значения цвета.
Если это поможет вам, пожалуйста, отметьте мой ответ галочкой
Комментарии:
1. ооо. в этом состоянии могут быть какие-то проблемы. Еще какая-нибудь помощь?