Working with Angular Material
has posed challenges for me, particularly in grasping the intricacies of the $scope.apply
functionality. Whenever I attempt to notify the UI of changes by invoking apply
, it consistently fails with an error. While similar questions exist on SO, my unique situation involves data not being stored by the scope
but rather by the controller instance itself.
It's worth noting that I've opted to utilize TypeScript
for my controller implementation, which seems somewhat unconventional given that most sample code I've come across features inline controller implementations directly within the view.
This is a snippet of what my controller looks like...
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;
}
}
The controller showcases the querySampleData
method, responsible for fetching data from a remote service using IHttpService
for asynchronous API calls. The way the controller is utilized in the view is as follows...
<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>
The initialization of the controller proceeds smoothly; all dependencies are appropriately injected into the controller, and the binding to the querySampleData
method operates as anticipated (triggered when the button is clicked). Despite assigning the retrieved data to the model, the UI does not update accordingly. As a workaround, I included a call to the $apply
method to inform the UI of changes, only to encounter the aforementioned error.
Update:
Referencing the documentation at: https://docs.angularjs.org/error/$rootScope/inprog suggests replacing $apply
with $timeout
for ensuring asynchronous execution. Although this resolves the error, it unfortunately doesn't reflect in UI updates...