Angular2 ngStyle не обновляется при нажатии

#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
введите описание изображения здесь

Демо-версия Stackblitz

Комментарии:

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.log

5. можете ли вы создать минимальную демонстрационную версию 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. ооо. в этом состоянии могут быть какие-то проблемы. Еще какая-нибудь помощь?