Reputation: 4123
How do you initialize isolate scope for an AngularJS directive when using a strongly-typed interface? If you want to use a model interface as well as the "@"
"="
and "&"
binding symbols, it seems you confuse the compiler because you can't assign a string variable to properties with incompatible types.
For instance:
module widgets {
'use strict';
export interface IWidget extends ng.IScope {
removed: boolean;
onChanged: ()=>void;
description: string;
toggle:()=>void;
}
export class Widget implements ng.IDirective {
public templateUrl = 'app/widgets/widget.html';
public restrict = 'E';
public scope: IWidget = {
removed: "@",
onChanged: "&",
description: "="
};
public link: (scope: IWidget, element: ng.IAugmentedJQuery,
attrs: ng.IAttributes) => void;
static factory(): any {
/* @ngInject */
var directive = () => {
return new Widget();
};
return directive;
}
constructor() {
this.link = (scope: IWidget, element: ng.IAugmentedJQuery,
attrs: ng.IAttributes) => {
var init = () => {
scope.toggle = this._toggle.bind(this);
scope.$on('$destroy', this.destruct);
scope.$apply();
};
element.ready(init);
};
}
private _toggle() {
// updated: this throws the type error
this.scope.removed = !this.scope.removed;
}
private destruct() {
}
}
}
Given the above code, notice that onChanged
will produce compiler errors, because you can't assign a string "&" to a function.
You may get the following error:
2349 Cannot invoke an expression whose type lacks a call signature.
Or this error on the removed
property:
2322 Type 'boolean' is not assignable to type 'string'.
In fact, even if you use any
for the model the compiler still wont let you change the underlying type of a property after it is defined.
Is there any way to deal with this?
Upvotes: 2
Views: 297
Reputation: 123901
The issue here is the directive definition.
It expects scope to be kind of IDictionary<string, string>
, but type any
would work as well:
export class Widget implements ng.IDirective {
public templateUrl = 'app/widgets/widget.html';
public restrict = 'E';
//public scope: IWidget = {
public scope: any = {
removed: "@",
onChanged: "&",
description: "="
};
The scope
here, in the directive definition, is about describing how to handle html attributes (passed as a value
, or as function
...) . It does not have type IWidget
. That type IWidget
will come into play when the scope instance is passed to controller
or link
As said above, the IDictionary
will work as well:
public scope: {[key: string] : string} = {
//public scope: any = {
"removed": "@",
"onChanged": "&",
"description": "="
};
But the any : {...}
and simplified notation will do the same.
Upvotes: 1
Reputation: 276343
You may get the following error: 2349 Cannot invoke an expression whose type lacks a call signature.
The main cause is that scope
members need to be stringly linked (and one of the reason I am no longer an angular advocate).
The member onChanged
should be callable just fine e.g. :
public scope: IWidget = {
removed: "@",
onChanged: "&",
description: "="
};
public link: (scope: IWidget, element: ng.IAugmentedJQuery, attrs: ng.IAttributes) => void {
scope.onChanged(); // WILL WORK FINE
}
You are probably misusing the annotation IWidget
in your code (not provided with the question).
Upvotes: 2