Angular: как временно выделить элементы dom, которые только что изменились?

Прежде чем реализовывать решение самостоятельно, я хотел бы знать, есть ли простой способ изменить стиль элемента (краткое выделение), когда значение свойства, привязанного к данным, только что изменилось.

В моей DOM много элементов, поэтому я не хочу хранить и поддерживать выделенное свойство в компоненте.

Я хочу выделить элементы традиционной формы ввода:

    <tr field label="Lieu dépôt">
        <select class="cellinput" #lieuDepotBon [(ngModel)]="rapport.LieuDepotBon" (ngModelChange)="changeRapport({LieuDepotBon:$event})">
            <option [ngValue]="null"></option>
            <option [ngValue]="i" *ngFor="let depotBonChoice of DepotBonInterventionValues; let i = index">{{DepotBonIntervention[i]}}</option>
        </select>
    </tr>
    <tr field *ngIf="rapport.LieuDepotBon==DepotBonIntervention.Autre" label="Autre lieu">
        <input class="cellinput" #autreLieuDepotBon [(ngModel)]="rapport.AutreLieuDepotBon" (ngModelChange)="changeRapport({AutreLieuDepotBon:autreLieuDepotBon.value})" />
    </tr>

Я слышал о специальных стилях классов, установленных Angular2 для элемента с помощью директивы ngModel, которые могут помочь мне в том, что мне нужно, но я не мог найти больше об этом.


person Anthony Brenelière    schedule 18.05.2017    source источник
comment
этот вопрос относится только к input элементам? а что вы имеете в виду под changed? Я слышал о специальных стилях классов, установленных Angular2 - вы имеете в виду ng-dirty class? если да, попробуйте просто добавить стиль для input.ng-dirty {background-color: green}   -  person Max Koretskyi    schedule 18.05.2017
comment
Это характерно для элементов с директивой ngModel. Кажется, что ng-dirty / ng-touched не дает решения, потому что они зависят от действий пользователя над элементом управления. В моем случае изменения не выполняются пользователем. Это просто изменение модели данных.   -  person Anthony Brenelière    schedule 18.05.2017
comment
В моем случае изменения не выполняются пользователем. - можете ли вы показать пример?   -  person Max Koretskyi    schedule 18.05.2017
comment
Изменения производятся путем слияния структур данных, для этого я использую lodash. Вот примеры Lodash.merge (updatedInter, newData). Мои элементы управления формой привязаны к некоторым данным этих объединенных структур.   -  person Anthony Brenelière    schedule 18.05.2017
comment
ну может можно поставить простой плункер?   -  person Max Koretskyi    schedule 18.05.2017
comment
Может, уже помогает перепрошивка Пайнфом Хрома? developers.google.com/ веб / основы / производительность / рендеринг /   -  person EffGee    schedule 18.05.2017
comment
Вы используете ng-repeat, чтобы показать эти объединенные данные?   -  person Paras    schedule 31.05.2017
comment
Нужно отдать пнкр   -  person Vamshi    schedule 11.06.2017
comment
Может, ты сможешь использовать valueChanges: Observable<any>. (генерирует событие каждый раз, когда значение элемента управления изменяется в пользовательском интерфейсе или программно.) Установите флажок Документация по Angular для получения дополнительной информации.   -  person lucascurti    schedule 14.06.2017
comment
Здесь есть хорошая статья с полным решением этой проблемы: ngmilk.rocks/2015/12/18/ - я использовал это в прошлом, чтобы делать то, что вы здесь описываете.   -  person Matt Andrews    schedule 05.12.2017


Ответы (3)


Самый простой и чистый способ, который я могу придумать, - это реализовать 2 класса css следующим образом:

.highlight{
    background-color: #FF0;
}
.kill-highlight{
    background-color: #AD310B;
    -webkit-transition: background-color 1000ms linear;
    -ms-transition: background-color 1000ms linear;
    transition: background-color 1000ms linear;
}

а затем воздействовать на них обоих последовательно на элемент. надеюсь, это поможет

person Taha Zgued    schedule 28.06.2017
comment
Точнее, мой вопрос касался того, как повлиять на классы css, когда в модели происходят изменения. Я выложу решение. - person Anthony Brenelière; 04.01.2018

Вот мое решение.

Я хотел выделить данные в форме, которые изменяются другими пользователями в режиме реального времени.

В моей HTML-форме я заменил собственные элементы html на компоненты Angular. Для каждого типа нативного элемента я создал новый компонент Angular с поддержкой Highlight. Каждый компонент реализует интерфейс Angular ControlValueAccessor.

В родительской форме заменил родной элемент:

<input [(ngModel)]="itinerary.DetailWeather" />

моим настраиваемым элементом:

<reactive-input [(ngModel)]="itinerary.DetailWeather"></reactive-input>

Когда Angular вызывает detectChanges () для родительской формы, он проверяет все данные, которые используются в качестве входных данных компонентами формы.

Если компонент является ControlValueAccessor и в модели приложения произошло изменение, он вызывает метод ControlValueAccessor. writeValue (value). Это метод, который вызывается при изменении данных в памяти. Я использую его как ловушку, чтобы временно обновить стиль, чтобы добавить выделения.

Вот кастомный элемент. Я использовал Angular Animations для обновления цвета границы и возврата к исходному цвету.

import { Component, Input, forwardRef, ChangeDetectorRef } from '@angular/core';
import { ControlValueAccessor,  NG_VALUE_ACCESSOR  } from '@angular/forms';
import { trigger, state, style, animate, transition, keyframes } from '@angular/animations';

@Component(
{
  selector: 'reactive-input',
  template: `<input class="cellinput" [(ngModel)]="value" [@updatingTrigger]="updatingState" />`,
  styles: [`.cellinput {  padding: 4px }`],
  animations: [
    trigger( 
      'updatingTrigger', [
        transition('* => otherWriting', animate(1000, keyframes([
          style ({ 'border-color' : 'var( --change-detect-color )', offset: 0 }),
          style ({ 'border-color' : 'var( --main-color )', offset: 1 })
        ])))
    ])
  ],
  providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ReactiveInputComponent), multi: true } ]
})
export class ReactiveInputComponent implements ControlValueAccessor {

  public updatingState : string = null;
  _value = '';

  // stores the action in the attribute (onModelChange) in the html template:
  propagateChange:any = ( change ) => {};

  constructor( private ref: ChangeDetectorRef ) { }

  // change from the model
  writeValue(value: any): void
  {
    this._value = value; 
    this.updatingState = 'otherWriting';

    window.setTimeout( () => {
      this.updatingState = null;
    }, 100 );

    // model value has change so changes must be detected (case ChangeDetectorStrategy is OnPush)
    this.ref.detectChanges();
  }

  // change from the UI
  set value(event: any)
  {
    this._value = event;
    this.propagateChange(event);
    this.updatingState = null;
  }

  get value()
  {
    return this._value;
  }

  registerOnChange(fn: any): void { this.propagateChange = fn; }
  registerOnTouched(fn: () => void): void {}
  setDisabledState?(isDisabled: boolean): void {};
}
person Anthony Brenelière    schedule 04.01.2018

Чтобы на мгновение выделить элемент DOM, используйте setTimeout() для добавления или удаления класса CSS.

проверить демонстрацию

HTML

<mat-form-field [ngClass]="{'changed': isChanged}">
  <mat-select [(ngModel)]="yourModel" (ngModelChange)="modelChanged($event)">
     <mat-option value="1">1</mat-option>
     <mat-option value="2">2</mat-option>
     <mat-option value="3">3</mat-option>
  </mat-select>
</mat-form-field>

Машинопись

isChanged: boolean = false
modelChanged(value) {
   console.log('model changed')

   this.isChanged = true
   setTimeout(() => {
       this.isChanged = false
   }, 1000);
}

CSS

.changed {
    transition: color 0.4s ease-in, text-shadow 0.4s ease-in, background-color 0.5s linear 0s;
    text-shadow: #bbb 2px 2px 2px;
    background-color: #ffffcc;
    color: #BF1722;
}

Примечание. если ваше приложение изменяется в миллисекундах, вам следует уменьшить время setTimeout() до 0,5 с или 0,3 с в соответствии с требованиями вашего приложения.

Благодарим Инго Бюрка за указание на эту проблему.

person WasiF    schedule 13.08.2018
comment
Это ужасно сломается, когда придет несколько обновлений. - person Ingo Bürk; 13.08.2018
comment
не могли бы вы объяснить, какие ужасные поломки могут произойти? - person WasiF; 13.08.2018
comment
если у вас есть 3 обновления одновременно, он обновит первое, подождет 1 с, запустит второе, подождет 1 с, запустит третье - person sheplu; 13.08.2018
comment
Когда элемент обновляется, он выделяет этот элемент на 1 с, чтобы пользователь показал успешное обновление. - person WasiF; 13.08.2018
comment
Я думаю, что вы неправильно поняли, или я не понимаю вашей точки зрения. если вы можете изменить, пожалуйста, сделайте это, сделайте это лучше, я хочу поучиться у вас. Как сделать так, чтобы пользователь лучше указывал на успешное изменение - person WasiF; 13.08.2018
comment
Представьте, что modelChange вызывается при t = 0 с и снова и t = 990 мс. После второго вызова таймаут от первого вызова установит isChanged в ложное значение всего через 10 мс вместо одной секунды, поскольку последовательные тайм-ауты независимы и конкурируют друг с другом. Если вы хотите научиться его улучшать, вы должны сами задать вопрос. - person Ingo Bürk; 13.08.2018
comment
Ваше возражение является обоснованным, и его решение заключается в том, что если ваша модель быстро изменится, вам следует изменить 1,0 с на 0,5 с или 0,3 с. Это зависит от требований приложения. - person WasiF; 13.08.2018