Обнаружение изменений в глубоко вложенном объекте для изменения NgStyle из службы с использованием Angular - PullRequest
0 голосов
/ 15 апреля 2020

У меня есть элемент HTML, для которого мне нужно изменить атрибут стиля, используя [ngStyle]. Для этого я создал переменную компонента с именем templateStyle и установил для нее значение в пределах объекта, предоставленного созданной мной службой с именем componentStyles, которая выглядит следующим образом:

base.component. ts

ngOnInit() {
  // returns a nested object of styles from my database
  var componentStyles = await this.styleService.componentStyles$.pipe(first()).toPromise();

  // I check to see if the style I need to set exists on the object, if it does, I add it
  this.templateStyle = {
    'min-height': componentStyles.customAttributes.sectionHeight != null ? `${componentStyles.customAttributes.sectionHeight}px` : null;
  }
}

Эта переменная templateStyle присвоена моему div примерно так:

<div [ngStyle]="templateStyle"></div>

Теперь вот проблема:

Пользователь может изменить свойство sectionHeight, используя ползунок во всплывающем окне. Поэтому в моем всплывающем компоненте я получаю доступ к styleService.componentStyles$, чтобы получить ссылку на объект стиля, а затем я могу изменить sectionHeight в зависимости от значения ползунка следующим образом:

popup. component.ts in ngOnInit()

// call the same service to get reference to styles
var componentStyles = await this.styleService.componentStyles$.pipe(first()).toPromise();

this.slider.subscribe((change) => {
  // emits current value of slider (from 1 to 100)
  // this is the same property that is being assigned in the templateStyle variable in the
  // base component
  componentStyles.customAttributes.sectionHeight = change.detail.value;
})

Поскольку componentStyles является объектом и передается по ссылке, фактическое значение данных действительно изменяется, НО это не вызывает запуск Angular обнаружение изменений в базовом компоненте, поскольку новый объект templateStyle не переназначается (изменяется только значение componentStyles.customAttributes.sectionHeight). Это приводит к тому, что объект [ngStyle] не обновляется, а атрибут min-height не изменяется.

Поскольку мой текущий контекст находится во всплывающем окне, как я могу принудительно проверить объект templateStyle в моем базовом компоненте для проверки для изменений? Я понимаю, что могу сделать:

this.templateStyle = Object.assign({}, this.templateStyle), но ползунок находится в popup.component.ts и не имеет доступа к переменной templateStyle в базовом компоненте.

Каков наилучший способ go по этому поводу?


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

Простой способ - просто назначить css непосредственно из объекта службы, например, так:

<div [ngStyle]="{
    'min-height': `${componentStyles.customAttributes.sectionHeight}px`
}"

Этот работает , но он заставляет мой HTML выглядеть неряшливо, и я бы вместо этого установил вместо него переменную компонента , Спасибо!

Ответы [ 2 ]

0 голосов
/ 15 апреля 2020

Вы должны использовать общие или общие службы для связи между компонентами. Это особенно полезно, когда дочерние компоненты глубоко вложены. Мне нравится использовать BehaviorSubject в качестве средства связи.

В CommonService настройте BehaviorSubject Тема / Наблюдаемый:

export class CommonService {

  private heightBehavior = new BehaviorSubject<number>(20);
  height$ = this.heightBehavior.asObservable();

  setHeight(value: number) {
    this.heightBehavior.next(value);
  }
}

В ChildComponent введите сервис и используйте его для установки и выдачи новых значений, в данном случае высоты при изменении значения ползунка:

export class ChildComponent {

  constructor(private commonService: CommonService) { }

  changeValue(value: number) {
    this.commonService.setHeight(value);
  }
}

В родительском компоненте внедрите службу и подпишитесь на открытую Наблюдаемую. (Вы также можете сделать это в ngOnInit, но для простоты давайте поместим это в конструктор):

export class AppComponent {
  divStyle = { height: "20px" };

  constructor(private commonService: CommonService) {
    this.commonService.height$.subscribe(val => 
      this.divStyle = { height: val + "px" }
    )
  }
}

В шаблоне, как вы предложили, вы можете использовать ngStyle для установки высоты:

<div [ngStyle]="divStyle"></div>

Проверьте демонстрацию Stackblitz: https://stackblitz.com/edit/angular-kynfwa

0 голосов
/ 15 апреля 2020

Я бы лично отнесся к этому случаю наличия «стиля стиля». Подход, который я бы использовал, состоит в том, чтобы вместо доступа этих компонентов к объекту из сервиса (поскольку я не вижу .subscribe ()) вместо этого использовать SUBJECT (rx js) для управления вашими стилями. и, в частности, BehaviorSubject .

В этом случае вы должны создать BehaviorSubject в вашем сервисе, присвоить ему начальное значение из некоторого вызова базы данных, а также в вашем всплывающем окне и ваш базовый компонент подписаться на него. Если вы хотите отправить изменения, вызванные вашим всплывающим окном, вы должны использовать subjectname.next (styleObject). Если это простая модификация существующего объекта стиля, вы можете сохранить локальную копию в вашем файле popup.ts для ссылки и изменения перед его генерацией.

Если ваш шаблон все еще не обновляется, когда это происходит, go впереди и выполните ручное обнаружение изменений: https://angular.io/api/core/ChangeDetectorRef

Просто введите сервис и вызовите cdref. detectChanges (), где происходит изменение

Удачного кодирования!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...