Reputation: 973
I have written custom angular element directive, which shows/hides loading indicator based on condition evaluated on service call. The directive is applied as element to element. The directive works fine, but the problem the content is of the applied element not hidding.
Here is my directive:
export interface ILoadingIndicatorAttr extends ng.IAttributes {
efpLoadingIndicator: string;
}
export interface ILoadingIndicatorscope extends ng.IScope {
loading: boolean;
}
export class LoadingIndicator implements ng.IDirective {
public restrict: string = 'A';
public replace: boolean = true;
static $inject = ["$compile", "$templateRequest", "$timeout"];
constructor(public _compile: ng.ICompileService, private templateService: ng.ITemplateRequestService, private timeout: ng.ITimeoutService) {
};
link = (scope: ILoadingIndicatorscope, element: ng.IAugmentedJQuery, attrs: ILoadingIndicatorAttr, ngModel: ng.INgModelController): void => {
var tempThis = this;
var templateUrl: string = 'app/modules/common/directives/loadingIndicator/loadingIndicator.tmpl.html';
attrs.$observe('efpLoadingIndicator', () => {
if (attrs.efpLoadingIndicator == "true") {
this.timeout(() => {
if (attrs.efpLoadingIndicator == "true") {
scope.loading = true;
tempThis.resolveTemplate(templateUrl).then((html: ng.IAugmentedJQuery) => {
tempThis._compile(html)(scope).appendTo(element);
});
}
else {
scope.loading = false;
}
}, 1000);
}
else {
scope.loading = false;
}
});
}
resolveTemplate = (templateUrl: string): ng.IPromise<ng.IAugmentedJQuery> => {
return this.templateService(templateUrl).then((html: string) => {
return angular.element(html);
});
}
}
Here is how it is applied:
<div efp-loading-indicator ={{vm.isLoading}}>
<select> </select>
</div
I want to hide the content of div when loading indicator is present, show when loading indicator is off. I know i can use ng-show on child elements but don't want to do that since I want to reuse this directive.
Upvotes: 0
Views: 217
Reputation: 1182
The problem is that this
is not what you expect in the link function. At that point,this
will be referring to the window
object (and thus tempThis
too).
If you need to use the link
function, you have to rebind it to this
in the constructor, where this
is referring to the class:
export interface ILoadingIndicatorAttr extends ng.IAttributes {
efpLoadingIndicator: string;
}
export interface ILoadingIndicatorscope extends ng.IScope {
loading: boolean;
}
export class LoadingIndicator implements ng.IDirective {
public restrict: string = 'A';
public replace: boolean = true;
link:(scope: ILoadingIndicatorscope, element: ng.IAugmentedJQuery, attrs: ILoadingIndicatorAttr, ngModel: ng.INgModelController)=> void
static $inject = ["$compile", "$templateRequest", "$timeout"];
constructor(public _compile: ng.ICompileService, private templateService: ng.ITemplateRequestService, private timeout: ng.ITimeoutService) {
this.link = this.myLink.bind(this);
};
myLink(scope: ILoadingIndicatorscope, element: ng.IAugmentedJQuery, attrs: ILoadingIndicatorAttr, ngModel: ng.INgModelController): void => {
var tempThis = this;
var templateUrl: string = 'app/modules/common/directives/loadingIndicator/loadingIndicator.tmpl.html';
attrs.$observe('efpLoadingIndicator', () => {
if (attrs.efpLoadingIndicator == "true") {
this.timeout(() => {
if (attrs.efpLoadingIndicator == "true") {
scope.loading = true;
tempThis.resolveTemplate(templateUrl).then((html: ng.IAugmentedJQuery) => {
tempThis._compile(html)(scope).appendTo(element);
});
}
else {
scope.loading = false;
}
}, 1000);
}
else {
scope.loading = false;
}
});
}
resolveTemplate = (templateUrl: string): ng.IPromise<ng.IAugmentedJQuery> =>{
return this.templateService(templateUrl).then((html: string) => {
return angular.element(html);
});
}
}
Upvotes: 0