[英]Angular2 Data binding for Primeng autocomplete component
Am using Angular2: 2.1.0
and Primeng: 1.0.0
,我正在使用Angular2: 2.1.0
和Primeng: 1.0.0
,
I want Autocomplete
component to bind to my object's key
and show object's value
in UI.我希望Autocomplete
组件绑定到我的object's key
并在 UI 中显示object's value
。
Here the Object is ,这里的对象是,
[{
"user_id": 101,
"user_name": "John"
},
{
"user_id": 101,
"user_name": "Ganesh"
},
{
"user_id": 101,
"user_name": "Irfan"
}]
app.component.html应用程序组件.html
<p-autoComplete [(ngModel)]="userId" placeholder="User Search..." field="user_name" [suggestions]="suggestionList" (completeMethod)="userSearch($event)"></p-autoComplete>
Using field
attribute in autocomplete i can show my object's value
in UI screen, but the entire object is binded to userId
在自动完成中使用field
属性我可以在 UI 屏幕中显示我的object's value
,但整个对象都绑定到userId
How can i make binding user_id
of selected object to userId
?如何将所选对象的user_id
绑定到userId
?
I had the same issue and actually ended using a separate method to capture the value我有同样的问题,实际上结束使用单独的方法来捕获值
captureId(event: any) {
this.userId = event.user_id;
}
And the actual use和实际使用
<p-autoComplete (onSelect)="captureId($event)" ...
@NTN-JAVA I have done this my using field property. @NTN-JAVA 我已经使用字段属性完成了此操作。
<p-autoComplete [(ngModel)]="userName" [suggestions]="filteredBrands" name="guestType" (completeMethod)="filterBrands($event)" [size]="12" [minLength]="1" field="user_name" inputStyleClass="txt-box" placeholder="Hint: type 'v' or 'f'" [dropdown]="true" (onDropdownClick)="handleDropdownClick($event)"> </p-autoComplete>
guestDetails = [{ "user_id": 101, "user_name": "John" }, { "user_id": 102, "user_name": "Ganesh" }, { "user_id": 103, "user_name": "Irfan" }] **Javascript** handleDropdownClick() { this.filteredBrands = []; setTimeout(() => { this.filteredBrands = guestDetails; }, 100); }
To summarize my understanding of the question and discussion so far:总结我到目前为止对问题和讨论的理解:
This can be achieved in a generic way by wrapping the ControlValueAccessor interface that autocomplete (and all other input components in angular) implements.这可以通过包装自动完成(以及 angular 中的所有其他输入组件)实现的 ControlValueAccessor 接口以通用方式实现。 This wrapper can do the transformation.这个包装器可以进行转换。 ngModel, formControl or formControlName directive is then used on the wrapper.然后在包装器上使用 ngModel、formControl 或 formControlName 指令。
I have created a plunkr to show this approach.我创建了一个plunkr来展示这种方法。 It uses "Country" instead of "User":它使用“国家”而不是“用户”:
<control-value-mapper [formControl]="control" [toModel]="idOfCountry" [fromModel]="countryForId" >
<p-autoComplete #cvDelegate
[suggestions]="results"
(completeMethod)="search($event)"
field="name"
dataKey="id">
</p-autoComplete>
</control-value-mapper>
The ControlValueMapper looks like this: ControlValueMapper 看起来像这样:
@Component({
selector: 'control-value-mapper',
template: '<ng-content></ng-content>',
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ControlValueMapper),
multi: true
}]
})
export class ControlValueMapper implements ControlValueAccessor {
@ContentChild('cvDelegate')
delegate: ControlValueAccessor
@Input()
fromModel: (any) => any;
@Input()
toModel: (any) => any;
setDisabledState(isDisabled: boolean) {
this.delegate.setDisabledState(isDisabled);
}
writeValue(obj: any) {
this.delegate.writeValue(this.fromModel(obj));
}
registerOnChange(fn: any) {
this.delegate.registerOnChange(value => fn(this.toModel(value)));
}
registerOnTouched(fn: any) {
this.delegate.registerOnTouched(value => fn(this.toModel(value)));
}
}
"toModel" and "fromModel" are the functions that map from Country to its id and vice versa. "toModel" 和 "fromModel" 是从 Country 映射到其 id 的函数,反之亦然。
Note that this solution is probably 'longer' than others, but it can be re-used in all similar situations (with other input components than autocomplete).请注意,此解决方案可能比其他解决方案“更长”,但它可以在所有类似情况下重复使用(使用除自动完成以外的其他输入组件)。
I had found a solution an year ago and updating my answer for others.一年前我找到了一个解决方案,并为其他人更新了我的答案。 As stefan's
answer we need model mapping, but his answer looks large process.作为stefan's
回答,我们需要模型映射,但他的回答看起来是一个很大的过程。
I used primeng autocomplete component and created a own component called user-search
with @Input()
and @Output()
events.我使用了primeng 自动完成组件并使用@Input()
和@Output()
事件创建了一个名为user-search
的自己的组件。
Template ( user.search.component.html )模板( user.search.component.html )
<p-autoComplete [(ngModel)]="userObject" placeholder="User Search..." field="user_name" [suggestions]="userSuggesstionList"
(onSelect)="onUserSelect($event)" (completeMethod)="search($event)">
</p-autoComplete>
Component ( UserSearchComponent ),组件( UserSearchComponent ),
@Component({
selector: 'user-search',
templateUrl: 'user.search.component.html'
})
export class UserSearchComponent implements OnInit {
userSuggesstionList: any[] = [];
userObject: any;
constructor(
) { }
ngOnInit() {
}
// note that this must be named as the input model name + "Change"
@Output() userSelected: any = new EventEmitter();
@Output() userIdChange: any = new EventEmitter();
@Input()
set userId(userId: string) {
if (userId != null && userId != '') {
this.userObject = // Load user object from local cache / from service.
} else {
this.userObject = null;
}
}
get userId(): string {
if (this.userObject != null) {
return this.userObject.userId;
} else {
return null;
}
}
search(event) {
// your search logic.
}
onUserSelect(event) {
this.userIdChange.emit(event.userId);
this.userSelected.emit(event);
}
}
And the usage of user-search component is,用户搜索组件的用法是,
<user-search [(userId)]="user_id"></user-search>
Here the user_id given as input to user-search
component, user-search
component loads actual user object from cache/ from server as based on user_id
.这里将 user_id 作为输入给user-search
组件, user-search
组件根据user_id
从缓存/服务器加载实际用户对象。 once the user object gets loaded then p-autocomplete
will bind with userObject
and displayed the username in autocomplete box.一旦用户对象被加载, p-autocomplete
将与userObject
绑定并在自动完成框中显示用户名。
Once user selected from suggestion list, A default change event is triggered to update user_id
value in parent component.一旦用户从建议列表中选择,就会触发默认更改事件以更新父组件中的user_id
值。
Also you can avail the UserObject ie.你也可以利用 UserObject 即。 {user_id: 'xxx', user_name:'xxx'} in userSelected
event. {user_id: 'xxx', user_name:'xxx'} 在userSelected
事件中。
We can simply wrap primeNG's autocomplete inside a custom autocomplete component that implements ControlValueAccessor
interface.我们可以简单地将 primeNG 的自动完成包装在一个实现ControlValueAccessor
接口的自定义自动完成组件中。
The custom component will customize the data binding if a dataKey
is defined as an @Input
or keeps primeNG's default behavior if no dataKey
is defined.自定义组件将自定义数据如果结合dataKey
被定义为@Input
或保持如果没有primeNG的默认行为dataKey
定义。
In the following code I use only properties and events I need, but it can be applied to all properties and events provided by primeNG's API.在下面的代码中,我只使用了我需要的属性和事件,但它可以应用于 primeNG 的 API 提供的所有属性和事件。
Here is the HTML code :这是 HTML 代码:
<p-autoComplete (completeMethod)="completeMethod.emit($event)"
(onClear)="onClear.emit($event)"
(onDropdownClick)="onDropdownClick.emit($event)"
(onSelect)="select($event)"
[dataKey]="dataKey"
[delay]="delay"
[disabled]="disabled"
[dropdown]="dropdown"
[emptyMessage]="emptyMessage"
[field]="field"
[forceSelection]="forceSelection"
[maxlength]="maxLength"
[minLength]="minLength"
[multiple]="multiple"
[placeholder]="placeholder"
[readonly]="readonly"
[required]="required"
[styleClass]="styleClass"
[suggestions]="suggestions"
[unique]="unique"
[(ngModel)]="autoCompleteValue">
</p-autoComplete>
And here is the typescript code :这是打字稿代码:
import { Component, EventEmitter, forwardRef, Input, Output } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'mb-auto-complete',
templateUrl: './auto-complete.component.html',
styleUrls: ['./auto-complete.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AutoCompleteComponent),
multi: true
}
]
})
export class AutoCompleteComponent implements ControlValueAccessor {
@Input() dataKey: string = null;
@Input() delay: number = 300;
@Input() disabled: boolean;
@Input() dropdown: boolean = false;
@Input() emptyMessage: string = null;
@Input() field: any = null;
@Input() forceSelection: boolean = null;
@Input() maxLength: number = null;
@Input() minLength: number = 1;
@Input() multiple: boolean = false;
@Input() placeholder: string;
@Input() readonly: boolean = false;
@Input() required: boolean = false;
@Input() styleClass: string = null;
@Input() suggestions: any[] = [];
@Input() unique: boolean = true;
@Output() completeMethod: EventEmitter<any> = new EventEmitter<any>();
@Output() onClear: EventEmitter<any> = new EventEmitter<any>();
@Output() onDropdownClick: EventEmitter<any> = new EventEmitter<any>();
@Output() onSelect: EventEmitter<any> = new EventEmitter<any>();
private onChange = (value: any): void => { /**/ };
private onTouched = (): void => { /**/};
public autoCompleteValue: any;
public registerOnChange(fn: any): void {
this.onChange = fn;
}
public registerOnTouched(fn: any): void {
this.onTouched = fn;
}
public setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
public writeValue(value: any): void {
if (this.dataKey?.length > 0) {
this.autoCompleteValue = this.suggestions.filter((item: any) => item[this.dataKey] === value)[0];
} else {
this.autoCompleteValue = value;
}
}
public select(selectedValue: any): void {
const newValue: any = this.dataKey?.length > 0 ? selectedValue[this.dataKey] : selectedValue;
this.onSelect.emit(newValue);
this.onChange(newValue);
}
}
You can then use your custom component, everywhere you use <p-autoComplete ..>
you can replace it by <mb-autoComplete ..>
(of course except in the html of AutoCompleteComponent
where you must keep <p-autoComplete ..>
).然后你可以使用你的自定义组件,在你使用<p-autoComplete ..>
任何地方你都可以用<mb-autoComplete ..>
替换它(当然除了在AutoCompleteComponent
的 html 中你必须保留<p-autoComplete ..>
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.