Angular2 Вызов открытого метода из внешнего приложения и потеря привязки изменений

У меня есть общедоступный метод, который я предоставил window. Этот метод взаимодействует с Component и изменяет переменную, которую я наблюдаю в своем шаблоне. Но когда я меняю значение, *ngIf() не срабатывает.

app.component

constructor(private _public: PublicService,) {
        window.angular = {methods: this._public};
    }

Государственная служба

export class PublicService {

    constructor(
        private  _viewManager: ViewManagerComponent,
    ) {}

    CallMe(){
        this._viewManager.renderView('page1')
    }
}

LayoutManagerComponent

@Component({
    selector: 'view-manager',
    template: `<page *ngIf="view == 'page1'"></page>`
})
export class ViewManagerComponent {
    //This is the variable being watched
    view = "page";

    renderView = function(type){
        console.log(type)
        this.view = type;
        console.log(this.view)
    };
}

Итак, идея состоит в том, что при первоначальной загрузке представления оно пустое. Затем, когда я набираю angular.methods.CallMe(), он изменяет переменную view на page1, которая затем должна отображать html для компонента. Если я использую консольную функцию renderView, она успешно вызывается, просто вид не меняется.

---- Обновление - Все еще не работает -------

export class ViewManagerComponent {
    constructor(private zone:NgZone,private cdRef:ChangeDetectorRef) {

    }
    view = "page";

     @Output() renderView(type){
        // type is 'page'
        console.log(this.view)
        this.zone.run(() => {
            // type is 'page'
            console.log(this.view)
            this.view = type;
            // type is 'page1'
            console.log(this.view)
        });
        // type is 'page1'
        console.log(this.view)
        //cdRef errors: 
        //view-manager.component.ts:36 Uncaught TypeError: this.cdRef.detectChanges is not a function(…)
        this.cdRef.detectChanges();
    };

}

person Rob    schedule 11.10.2016    source источник


Ответы (1)


В этом случае Angular2 не знает, что ему нужно запустить обнаружение изменений, потому что изменение вызвано кодом, который выполняется за пределами зоны Angulars.

Явный запуск обнаружения изменений

contructor(private cdRef:ChangeDetectorRef) {}

someMethodCalledFromOutside() {
  // code that changes properties in this component 
  this.cdRef.detectChanges();
}

Запустите код, который явно изменяет свойства компонентов внутри зоны Angulars.

contructor(private zone:NgZone) {}

someMethodCalledFromOutside() {
  this.zone.run(() => {
  // code that changes properties in this component 
  });
}

Метод zone лучше подходит, когда // code that changes properties in this component не только изменяет свойства текущего компонента, но также вызывает изменения в других компонентах (например, this.router.navigate(), вызывает ссылки на методы методов других компонентов), потому что zone.run() выполняет код внутри зоны Angulars, и вы не не нужно явно заботиться об обнаружении изменений в каждом компоненте, где изменение может произойти из-за этого вызова.

Если вы используете function(...) вместо () =>, вероятно, вы получите неожиданное поведение с this в коде внутри компонента Angular.

См. также мой ответ на этот аналогичный вопрос для более подробной информации 36997723">Angular 2 — связь функций машинописного текста с внешними библиотеками js

обновить

export class ViewManagerComponent {
    constructor(private zone:NgZone,private cdRef:ChangeDetectorRef) {
      self = this;
    }
    view = "page";

     @Output() renderView(type){
        // type is 'page'
        console.log(self.view)
        self.zone.run(() => {
            // type is 'page'
            console.log(self.view)
            self.view = type;
            // type is 'page1'
            console.log(self.view)
        });
        // type is 'page1'
        console.log(self.view)
        self.cdRef.detectChanges();
    };

}
person Günter Zöchbauer    schedule 11.10.2016
comment
Спасибо. Я внес изменения и сначала попробовал this.zone.run, но это не сработало (ошибок нет). Затем я попробовал cfRef.detectChanges() и сначала пожаловался, что он не является провайдером. Я добавил в app.module, затем получил эту ошибку: view-manager.component.ts:30 Uncaught TypeError: this.cdRef.detectChanges is not a function(…) - person Rob; 11.10.2016
comment
Вероятно, это связано с тем, что this не указывает на ваш текущий экземпляр компонента, как указано в моем ответе. Ответ, на который я ссылался, должен предоставить решение для этого - person Günter Zöchbauer; 11.10.2016
comment
Я изменил свой код. См. выше. Я поместил несколько консолей до и после, чтобы отслеживать, и this, похоже, правильно определен. - person Rob; 11.10.2016
comment
Почему бы вам просто не изменить @Output() renderView = function(type){ на @Output() renderView(type){? - person Günter Zöchbauer; 11.10.2016
comment
Пожалуйста, добавьте сообщение об ошибке к вашему вопросу, если вы его получили. - person Günter Zöchbauer; 11.10.2016
comment
изменен формат представления рендеринга и добавлена ​​ошибка в комментарии к коду, когда я раскомментирую this.cdRef.detectChanges(); - person Rob; 11.10.2016
comment
Это сработало! Можете ли вы сказать мне, почему, чтобы я мог следить за такими проблемами? - person Rob; 11.10.2016
comment
Если вы передаете this.renderView, то this внутри renderView() указывает не на ViewManagerComponent, а на контекст, из которого он фактически вызывается (хорошая функция JS ;-)). Вы можете использовать window.xxx = this.renderView.bind(this); или window.xxx = (type) => this.renderView(type); или так, как я показал выше. Ваши console.log(), похоже, работали, но я предполагаю, что значения были только что установлены из предыдущих вызовов в контексте, на который указывал this. - person Günter Zöchbauer; 11.10.2016