$rootScope:inprog Действие уже выполняется

Я начал работать с Angular Material и с трудом понимаю проблему с функциональностью $scope.apply... всякий раз, когда я пытаюсь уведомить пользовательский интерфейс об изменениях, вызывая apply, происходит сбой с ошибкой. Я знаю, что на SO есть похожие вопросы, но в моем случае данные хранятся не scope, а экземпляром контроллера...

Я также использую TypeScript для реализации моего контроллера; не уверен, но это кажется довольно необычным, поскольку большинство примеров кода, которые я нашел, основаны на реализации встроенного контроллера прямо в представлении.

Мой контроллер выглядит так...

module MyApp {

    export class MyController {

        private scope: angular.IScope;
        private http: angular.IHttpService;

        public model: { data: SampleData } = { data: { } };

        constructor($scope: angular.IScope, $http: angular.IHttpService) {
            this.scope = $scope;
            this.http = $http;
        }

        public querySampleData(): void {

            const serviceEndpoint: string = "http://localhost:8080/api/";
            var promise: ng.IHttpPromise<SampleData> = this.http.get(serviceEndpoint + "sample", { });

            var callback: ng.IHttpPromiseCallback<SampleData> = (
                data: SampleData,
                status: number,
                headers: angular.IHttpHeaderGetter,
                config: angular.IRequestConfig) => {
                this.scope.apply(() => {
                    this.model.data = data;
                };
            };

            promise.success(callback);
        }
    }

    export interface SampleData {
        message? string;
    }
}

Контроллер предоставляет метод querySampleData, который получает некоторые данные из удаленной службы (он использует IHttpService для асинхронных вызовов API). Контроллер используется представлением следующим образом...

<html ng-app="app">
    <body ng-controller="MyController as c">
        <div>
            <button ng-click="c.querySampleData()" 
                    aria-label="Query sample data">Query sample data</button>
            <p>{{c.model.data.message}}</p>
        </div>
        ...
        <script src="../scripts/app.js"></script>
        <script type="text/javascript">
            var app = angular.module("app", ["ngMaterial"]);
            app.controller("MyController", [ "$scope", "$http", MyApp.MyController ]);
        </script>
    </body>
</html> 

Инициализация контроллера работает нормально; все зависимости правильно внедряются в контроллер, а также привязка к методу querySampleData работает, как и ожидалось (когда я нажимаю кнопку, метод вызывается). Если я назначаю полученные данные модели, пользовательский интерфейс не обновляется, поэтому я добавил вызов метода $apply, чтобы сообщить пользовательскому интерфейсу об изменениях... что дает мне ошибку, о которой я упоминал выше.

Обновление:

Документация по адресу: https://docs.angularjs.org/error/$rootScope/inprog рекомендует использовать $timeout вместо $apply для обеспечения асинхронного выполнения; конечно, это исправляет ошибку, но пользовательский интерфейс не меняется...


person Matze    schedule 30.03.2016    source источник


Ответы (2)


AngularJS обещает уже вызывать .apply() (под капотом) в своих обратных вызовах. Вы не можете снова вызвать .apply внутри обратных вызовов, поскольку они уже применяются, и ошибка «Выполняется» говорит именно об этом. Просто удалите вызов .apply, и он будет работать, если только у вас больше не возникнет ошибок.

person Luis Masuelli    schedule 30.03.2016
comment
Хорошо; Я понял, почему я не видел никаких изменений в пользовательском интерфейсе... это было потому, что я использовал псевдоним c вне его области... глупый я (-; Ваш ответ правильный; если привязка в порядке, нет нужно вручную вызвать apply. - person Matze; 30.03.2016

может быть, вы можете попробовать this.model.data = data;, а затем this.scope.apply();

person Alemndra    schedule 30.03.2016