В angular2, как получить onChanges для свойств, измененных на объект, отправленный для @Input

У меня есть директива, и на ней есть @Input, который принимает класс.

@Directive({selector: 'my-directive'})
@View({directives: [CORE_DIRECTIVES]})
export class MyDirective  {
    @Input() inputSettings : SettingsClass;
    @Input() count : number;

   onChanges(map) {
      console.log('onChanges');
    }
}

Директива используется в html:

  ...
  <my-directive [input-settings]="settings" [count]="settings.count"></my-directive>
  ...

Если параметр settings.count изменен, загорится onChanges. Если какое-либо другое свойство в классе настроек изменяется, оно не срабатывает.

Как определить, есть ли какое-либо изменение в настройках?

Ответ 1

Angular заметит только, если объект был изменен на другой объект (т.е. ссылка на объект изменена), поэтому ngOnChanges() не может использоваться для решения вашей проблемы. Подробнее см. сообщение в блоге Виктора Савки.

Вы можете реализовать метод ngDoCheck() в своем классе MyDirective. Этот крючок жизненного цикла называется "каждый раз, когда проверяются свойства ввода компонента или директивы". Используйте его для расширения обнаружения изменений путем выполнения специальной проверки. "

Чтобы реализовать свой собственный метод проверки, вам сначала нужно реализовать метод .equals() в классе SettingsClass, чтобы затем вы могли написать код в виде ngDoCheck():

ngDoCheck() {
   if(!this.inputSettings.equals(this.previousInputSettings)) {
      // inputSettings changed
      // some logic here to react to the change
      this.previousInputSettings = this.inputSettings;
   }
}

Ответ 2

Другое решение, которое полезно, когда у вас нет контроля над объектом, который вы передаете компоненту, - это использование ViewChild и прямой вызов метода для обновления объекта:

В дочерний компонент добавьте функцию, например:

public updateSettings(obj: SettingsClass) {
    this.inputSettings  = obj;
}

А в родительском компоненте вызовите функцию updateSettings:

@Component({
    selector: 'app-mycomponnent',
    templateUrl: './my.component.html',
    styleUrls: ['./my.component.css']
})
export class PlayComponent implements OnInit {

    @ViewChild(MyDirectiveComponent,{static: false}) mydirective;

    elsewhereinthecode() {
        // When you need to update call : 
        mydirective.updateSettings(settingsObject);
    }
}

Ответ 3

В вашем html вы не можете использовать CamelCase, измените его на

<my-directive [input-settings]="settings" [count]="settings.count"></my-directive>