如何在“角度编写代码方式”中的angular2中正确连接两个指令或指令到组件(也是一个指令)?
由于关于angular2的文档仍然非常缺乏,所以非常感谢任何见解或参考。
这是每个angular2示例显示的内容 - 通过string
绑定到 ngModel
:
@Component({
template: 'Hello <input type="text" [(ngModel)]="myVariable">!'
})
class ExampleComponent() {
myVariable: string = 'World';
}
假设我想在自定义组件上使用ngModel
,它不代表 string
s ,而是任何其他值,例如a number
或类或接口:
interface Customer {
name: string;
company: string;
phoneNumbers: string[];
addresses: Address[];
}
@Component({
selector: 'customer-editor',
template: `
<p>Customer editor for {{customer.name}}</p>
<div><input [(ngModel)]="customer.name"></div>`
})
class CustomerEditor {
customer: Customer;
}
为什么我可以使用ngModel
,当任何其他属性使数据绑定更容易时?好吧,我正在为angular2实现一个设计垫片,组件将像原生<input>
一样使用(或旁边):
<input name="name" [(ngModel)]="user.name">
<pretty-select name="country" [(ngModel)]="user.country" selectBy="countryCode">
<option value="us">United States of America</option>
<option value="uk">United Kingdom</option>
...
</pretty-select>
user.country
将是对象,而不是字符串:
interface Country {
countryCode: string,
countryName: string
}
class User {
name: string;
country: Country;
...
}
GitHub repository for this example
要将ngModel
指令提供的引用与我的CustomerEditor
组件相关联,目前我正在使用我自己的ControlValueAccessor
:(简化)
const CUSTOMER_VALUE_ACCESSOR: Provider = CONST_EXPR(
new Provider(NG_VALUE_ACCESSOR, {
useExisting: forwardRef(() => CustomerValueAccessor)
})
);
@Directive({
selector: 'customer-editor[ngModel]',
providers: [CUSTOMER_VALUE_ACCESSOR]
})
@Injectable()
class CustomerValueAccessor implements ControlValueAccessor {
private host: CustomerEditor;
constructor(element: ElementRef, viewManager: AppViewManager) {
let hostComponent: any = viewManager.getComponent(element);
if (hostComponent instanceof CustomerEditor) {
this.host = hostComponent;
}
}
writeValue(value: any): void {
if (this.host) { this.host.setCustomer(value); }
}
}
现在,令我不安的是ControlValueAccessor
是我获取对主机组件的引用的方式:
if (hostComponent instanceof CustomerEditor) {
this.host = hostComponent;
}
这不仅需要3个依赖项,其中一个应该足够(ElementRef
,AppViewManager
,CustomerEditor
),在运行时进行类型检查也感觉非常错误。
如何在angular2?
中获取对主机组件的引用的“正确”方法我尝试过的其他事情,但没有开始工作:
This answer by Thierry Templier注意到ControlValueAccessor构造函数中的组件类,它由angular注入:
class CustomerValueAccessor implements ControlValueAccessor {
constructor(private host: CustomerEditor) { }
}
不幸的是,这对我不起作用,并给了我一个例外:
无法解析'CustomerValueAccessor'的所有参数(未定义)。确保所有参数都使用Inject进行修饰或具有有效的类型注释,并且'CustomerValueAccessor'使用Injectable进行修饰。
使用@Host
:
class CustomerValueAccessor implements ControlValueAccessor {
constructor(@Host() private editor: CustomerEditor) { }
}
抛出与上述解决方案相同的例外情况。
使用@Optional
:
class CustomerValueAccessor implements ControlValueAccessor {
constructor(@Optional() private editor: CustomerEditor) { }
}
不会抛出异常,但CustomerEditor
未注入并保持null
。
由于角度变化/频繁变化,the specific versions I am working with might be relevant, which is angular2@2.0.0-beta.6
。
答案 0 :(得分:2)
Günter Zöchbauer的评论指出了我正确的方向。
要使用ngModel
绑定组件上的值,组件本身需要实现ControlValueAccessor
接口并向自身提供forwardRef
在组件配置的providers:
键中:
const CUSTOMER_VALUE_ACCESSOR: Provider = CONST_EXPR(
new Provider(NG_VALUE_ACCESSOR, {
useExisting: forwardRef(() => CustomerEditor),
multi: true
})
);
@Component({
selector: 'customer-editor',
template: `template for our customer editor`,
providers: [CUSTOMER_VALUE_ACCESSOR]
})
class CustomerEditor implements ControlValueAccessor {
customer: Customer;
onChange: Function = () => {};
onTouched: Function = () => {};
writeValue(customer: Customer): void {
this.customer = customer;
}
registerOnChange(fn: Function): void {
this.onChange = fn;
}
registerOnTouched(fn: Function): void {
this.onTouched = fn;
}
}
来自父组件的用法:
@Component({
selector: 'customer-list',
template: `
<h2>Customers:</h2>
<p *ngFor="#c of customers">
<a (click)="editedCustomer = c">Edit {{c.name}}</a>
</p>
<hr>
<customer-editor *ngIf="editedCustomer" [(ngModel)]="editedCustomer">
</customer-editor>`,
directives: [CustomerEditor]
})
export class CustomerList {
private customers: Customer[];
private editedCustomer: Customer = 0;
constructor(testData: TestDataProvider) {
this.customers = testData.getCustomers();
}
}
ControlValueAccessor
的每个示例总是显示如何在主机组件上使用单独的类或指令,从未在主机组件类本身上实现。
答案 1 :(得分:0)
在您的示例中,似乎您的CustomerValueAccessor
指令附加在CustomerComponent
组件(一个是选择器customer-editor
)上,而不是CustomerEditor
类型的指令。我认为这就是为什么你不能注射它的原因。
CustomEditor
对应什么?