Angular2 не запускает changeDetection после клика

Angular2 не запускает ChangeDetection после события click. Приведенные ниже фрагменты кода предназначены для передачи данных из одного компонента в другой.

onClickEvent

 (click)="$event.preventDefault(); setApartmentObject(FlatObject)";

КвартираОбзорКомпонент

constructor(private _apart:ApartmentService) {}

setApartmentObject(flat:ApartmentObject) {
    this._apart.setApartmentDetails(flat);
}

КвартираСервис

Injectable()
export class ApartmentService {

  apartmentDetails:ApartmentObject

  getApartmentDetails():Observable<ApartmentObject> {
      return Observable.create((observer) => {
          observer.next(this.apartmentDetails);
          observer.complete();
      });
  }

  setApartmentDetails(value:ApartmentObject) {
      this.apartmentDetails = value;
  }
}

КвартираДетальКомпонент

constructor(private _apart:ApartmentService)

get apartmentDetails() {
    this._apart.getApartmentDetails().subscribe(data => {
        this._apartmentDetails = data;
    });
    return this._apartmentDetails;
}

В HTML-файле

 <p><strong>{{apartmentDetails.name || 'Musterwohnung'}}</strong></p>

Я также пытался решить эту проблему с помощью генератора событий, но безуспешно. Работает только следующее грязное исправление:

constructor(private _ref:ChangeDetectorRef) {
  this._ref.detach();
  setInterval(() => {
     this._ref.detectChanges();
  }, 300);
}

person Zero    schedule 22.07.2016    source источник
comment
Я не понимаю проблемы. Запускает ли Angular обнаружение изменений, и вы хотите его предотвратить, или вы хотите, чтобы обнаружение изменений выполнялось, а Angular — нет?   -  person Günter Zöchbauer    schedule 22.07.2016
comment
Что вы ожидаете? Как вы думаете, почему Angular2 не выполняет обнаружение изменений?   -  person Günter Zöchbauer    schedule 22.07.2016
comment
Проблема в том, что angular должен загружать данные из одного объекта ApartmentOverviewComponent в ApartmentDetailComponent и перерисовывать с фактическими данными. Я получаю данные в ApartmentDetailComponent, но представление не перерисовывается, потому что changeDetection не срабатывает. И я не знаю, почему.   -  person Zero    schedule 22.07.2016
comment
Я почти уверен, что это не связано с тем, что обнаружение изменений не работает. Вы получаете какую-либо ошибку или предупреждение в консоли браузера?   -  person Günter Zöchbauer    schedule 22.07.2016
comment
Ошибок и предупреждений в консоли нет. Функция apartmentDetails() правильно устанавливает данные, но angular не перерисовывает представление.   -  person Zero    schedule 22.07.2016
comment
Откуда FlatObject в setApartmentObject(FlatObject)"? Похоже на опечатку. Имена свойств обычно пишутся строчными буквами, а имена типов — прописными. Типы нельзя использовать таким образом в шаблоне.   -  person Günter Zöchbauer    schedule 22.07.2016
comment
Можете ли вы поместить оператор консоли в функцию подписки get apartmentDetails(), чтобы проверить, вызывается ли подписка. Перед этим утверждением 'this._apartmentDetails = data;'. Я думаю, вам нужно отправить следующее значение наблюдателя из службы   -  person Arpit Agarwal    schedule 22.07.2016


Ответы (1)


Есть некоторые проблемы с вашим кодом, которые фактически препятствуют чтению значения.

Прежде всего — в вашем сервисе — когда вы устанавливаете значение, вы просто делаете это на экземпляре сервиса, а не передаете его наблюдаемому объекту. Наблюдаемый просто не может знать, что значение изменилось, поэтому он не будет генерировать событие изменения (следующее). Вот почему ApartmentOverviewComponent. setApartmentObject() ничего не делает. Чтобы на самом деле наполнить наблюдаемое данными, вам нужно использовать Subject.

В ApartmentDetailComponent в этом простом сценарии (где данные всегда предоставляются синхронно) вы могли бы получить значение так, как вы пытаетесь это сделать. Но, как упоминалось ранее, данные никогда не изменятся. Также необходимо хранить данные в поле _apartmentDetails экземпляра компонента. Вы можете использовать наблюдаемое в своем шаблоне.

Рабочая реализация такова:

@Injectable()
class ApartmentService {
  // BehaviorSubject is a type of an Observable that can be manually fed with data
  // and returns it's last value to any subscriber.
  apartmentDetails = new BehaviorSubject<ApartmentObject>({name: 'Musterwohnung'});

  // Instead of using a property of the service, just inform the
  // subject about knew data and let it spread the change for you.
  setApartmentDetails(value: ApartmentObject) {
    this.apartmentDetails.next(value);
  }
}

@Component({
  selector: 'overview-cmp',
  // Side note: you don't need to .preventDefault() here.
  template: `<a (click)="setApartmentObject({name: 'Shiny Aparament'})">click</a>`
})
class ApartmentOverviewComponent {
  constructor(private apartService: ApartmentService) {}

  // Works same as before.
  setApartmentObject(flat: ApartmentObject) {
    this.apartService.setApartmentDetails(flat);
  }
}

@Component({
  selector: 'details-cmp',
  // Use the 'async' pipe to access the data stored in an Observable
  // object. Also, to secure the code, use '?' to safely access the property.
  template: `<p><strong>{{(details | async)?.name}}</strong></p>`
})
class Apartament {
  // This is the observable with data.
  details: Observable<ApartmentObject>;

  constructor(private apartService: ApartmentService) {}

  // When component initialises, assign the observable data from the service
  ngOnInit() {
    this.details = this.apartService.apartmentDetails;
  }
}
person Mateusz Kocz    schedule 22.07.2016