Angular - syncfusion ejs autocomplete selecting incorrect value - autocomplete

Using a Syncfusion EJS Autocomplete element in a search box.
The issue being reported is that the user is not able to select the value searched
I know the issue, is because the data passed to the AutoComplete has some duplicate values, but they are distinct based on a second value.
The code below hopefully show the issue
<div class="control-section" style="margin:130px auto;width:300px">
<ejs-autocomplete
id="sample-list"
#sample
[dataSource]="countriesData"
[autofill]="isBool"
[fields]="fields"
(select)='selectIssuer($event)'
filterType="Contains"
>
<ng-template #itemTemplate let-data>
<!--set the value to itemTemplate property-->
<div class='item'>
<div>{{data.Name}} -- {{data.Structure != 'SPV' ? 'BT' : data.Structure}}</div>
</div>
</ng-template>
</ejs-autocomplete>
</div>
/**
* AutoComplete Highlight Sample
*/
import { Component, ViewChild } from '#angular/core';
import { AutoCompleteComponent } from '#syncfusion/ej2-angular-dropdowns';
#Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css'],
})
export class AppComponent {
public countriesData = [
{ Name: 'Client 1' , Id: 'A3D49279-18DC-40FB-B843-B6207518B379', Structure: 'BT'},
{ Name: 'Client 1' , Id: '77ED2BD8-2309-4792-9264-01DEAFC3227E', Structure: 'SPV'},
{ Name: 'Client 2' , Id: 'BA017D4F-DD5C-4F2D-852C-DD17AF209436', Structure: 'BT'},
{ Name: 'Client 3' , Id: '78FCDCB9-06EA-4D9B-A352-171B1594AE24', Structure: 'SPV'},
{ Name: 'Client 4' , Id: '48C3168A-FA2A-4EF7-B184-61F18C47AB6D', Structure: 'BT'},
{ Name: 'Client 4' , Id: 'E734CA83-91FF-4475-B35E-BE232ACBF137', Structure: 'SPV'}
];
public fields: Object = { value: 'Name' };
public isBool: Boolean = true;
}
selectIssuer(_issuer: any) {
this.getSearchIssuer.emit({ issuer: <CombinedIssuer>_issuer.itemData, clear: false });
}
AS is visible, some of the Client Names are the same, but what makes them distinct is the combination with the Structure.
The issue is that when a user selects say Client 4 that has an SPV Structure, it still loads the Client 4 with the BT structure.
Is it possible for the EJS Autocomplete to take in to consideration the combination of fields to make sure the correct item is selected or is is possible for the EJS Autocomplte to use the Item Id as well
Can it be possible to pass in the Id value to the Fields property ?

I was able to figure this out, so sharing my findings:
The additional code is shown below with ...
<ejs-autocomplete id='combinedIssuerSearch' #searchCombinedIssuers
[dataSource]='ixDispalyCombinedIssuerList'
[fields]='issuerFields'
ShowBorder='False'
(select)='selectIssuer($event)'
[placeholder]='defaultText'
[filterType]='issuerFilterType'
*(filtering)='onFiltering($event)'*
[showClearButton]="false"
class="auto-complete-search">
<ng-template #itemTemplate let-data>
<!--set the value to itemTemplate property-->
<div class='item'>
<div class='issuer-name'> {{data.Name}}</div>
<div class="ls_spv">{{data.Structure != 'SPV' ? 'BT' : data.Structure}}</div>
</div>
</ng-template>
</ejs-autocomplete>
in the ts file I added code to handle the OnFiltering event
onFiltering(args) {
args.preventDefaultAction = true;
var predicate = new Predicate('Name', 'contains', args.text, true);
predicate = predicate.or('Structure', 'contains', args.text, true);
var query = new Query();
query = args.text != '' ? query.where(predicate) : query;
args.updateData(this.ixDispalyCombinedIssuerList, query);
}

Related

Mapbox auto fill complete address

I use mapbox tools for my autofill place address autocomplete on my project Symfony
I want to know how can i extract full complete address in autofill, i have 2 inputs one for search and one hidden for get full/complete address
<mapbox-address-autofill>
{{ form_widget( form.address, {
'attr': {
'class': 'form-control form-control-solid font-weight-bold',
'placeholder': 'Adresse de départ',
'required': 'required',
'autocomplete': 'address-line1'
}
} ) }}
{{ form_widget( form.address_value, {
'attr': {
'autocomplete': 'full-address'
}
}) }}
</mapbox-address-autofill>
I have this but with tag 'full-addresse' 'complete' 'place_name'
No one workn if you have any solution for get full address to persist this in php Symfony project
"full_address" is a property of the feature object that is returned from a retrieve event, but does not automatically map to any HTML form field autocomplete value. The only object properties that get mapped to HTML elements are the ones corresponding to WHATWG standards, i.e.:
'street-address'
'address-line1'
'address-line2'
'address-line3'
'address-level1'
'address-level2'
'address-level3'
'address-level4'
'country'
'country-name'
'postal-code'
I'm not familiar with PHP, but a way to do this in Javascript would be something like:
const autofill = document.querySelector('mapbox-address-autofill');
const targetInput = document.getElementById('myTargetInput');
autofill.addEventListener('retrieve', (event) => {
const featureCollection = event.detail;
const feature = featureCollection[0];
const fullAddress = feature.properties.full_address;
targetInput.value = fullAddress;
});

Bootstrap-vue: Auto-select first hardcoded <option> in <b-form-select>

I'm using b-form-select with server-side generated option tags:
<b-form-select :state="errors.has('type') ? false : null"
v-model="type"
v-validate="'required'"
name="type"
plain>
<option value="note" >Note</option>
<option value="reminder" >Reminder</option>
</b-form-select>
When no data is set for this field I want to auto-select the first option in the list.
Is this possible? I have not found how to access the component's options from within my Vue instance.
your v-model should have the value of the first option.
example
<template>
<div>
<b-form-select v-model="selected" :options="options" />
<div class="mt-3">Selected: <strong>{{ selected }}</strong></div>
</div>
</template>
<script>
export default {
data() {
return {
selected: 'a',
options: [
{ value: null, text: 'Please select an option' },
{ value: 'a', text: 'This is First option' },
{ value: 'b', text: 'Selected Option' },
{ value: { C: '3PO' }, text: 'This is an option with object value' },
{ value: 'd', text: 'This one is disabled', disabled: true }
]
}
}
}
</script>
You can trigger this.selected=${firstOptionValue} when no data is set.
what if we don't know what the first option is. The list is generated?
if you have dynamic data, something like this will work.
<template>
<div>
<b-form-select v-model="selected" :options="options" />
<div class="mt-3">Selected: <strong>{{ selected }}</strong></div>
</div>
</template>
<script>
export default {
data() {
return {
selected: [],
options: [],
};
},
mounted: function() {
this.getOptions();
},
methods: {
getOptions() {
//Your logic goes here for data fetch from API
const options = res.data;
this.options = res.data;
this.selected = options[0].fieldName; // Assigns first index of Options to model
return options;
},
},
};
</script>
If your options are stored in a property which is loaded dynamically:
computed property
async computed (using AsyncComputed plugin)
through props, which may change
Then you can #Watch the property to set the first option.
That way the behavior of selecting the first item is separated from data-loading and your code is more understandable.
Example using Typescript and #AsyncComputed
export default class PersonComponent extends Vue {
selectedPersonId: string = undefined;
// ...
// Example method that loads persons data from API
#AsyncComputed()
async persons(): Promise<Person[]> {
return await apiClient.persons.getAll();
}
// Computed property that transforms api data to option list
get personSelectOptions() {
const persons = this.persons as Person[];
return persons.map((person) => ({
text: person.name,
value: person.id
}));
}
// Select the first person in the options list whenever the options change
#Watch('personSelectOptions')
automaticallySelectFirstPerson(persons: {value: string}[]) {
this.selectedPersonId = persons[0].value;
}
}

Angular: composite ControlValueAccessor to implement nested form

Composition of ControlValueAccessor to implement nested form is introduced in an Angular Connect 2017 presentation.
https://docs.google.com/presentation/d/e/2PACX-1vTS20UdnMGqA3ecrv7ww_7CDKQM8VgdH2tbHl94aXgEsYQ2cyjq62ydU3e3ZF_BaQ64kMyQa0INe2oI/pub?slide=id.g293d7d2b9d_1_1532
In this presentation, the speaker showed a way to implement custom form control which have multiple value (not only single string value but has two string field, like street and city). I want to implement it but I'm stuck. Sample app is here, does anybody know what should I correct?
https://stackblitz.com/edit/angular-h2ehwx
parent component
#Component({
selector: 'my-app',
template: `
<h1>Form</h1>
<form [formGroup]="form" (ngSubmit)="onSubmit(form.value)" novalidate>
<label>name</label>
<input formControlName="name">
<app-address-form formControlName="address"></app-address-form>
<button>submit</button>
</form>
`,
})
export class AppComponent {
#Input() name: string;
submitData = '';
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = fb.group({
name: 'foo bar',
address: fb.group({
city: 'baz',
town: 'qux',
})
});
}
onSubmit(v: any) {
console.log(v);
}
}
nested form component
#Component({
selector: 'app-address-form',
template: `
<div [formGroup]="form">
<label>city</label>
<input formControlName="city" (blur)="onTouched()">
<label>town</label>
<input formControlName="town" (blur)="onTouched()">
</div>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => AddressFormComponent)
}
]
})
export class AddressFormComponent implements ControlValueAccessor {
form: FormGroup;
onTouched: () => void = () => {};
writeValue(v: any) {
this.form.setValue(v, { emitEvent: false });
}
registerOnChange(fn: (v: any) => void) {
this.form.valueChanges.subscribe(fn);
}
setDisabledState(disabled: boolean) {
disabled ? this.form.disable() : this.form.enable();
}
registerOnTouched(fn: () => void) {
this.onTouched = fn;
}
}
and error message I got
ERROR TypeError: Cannot read property 'setValue' of undefined
at AddressFormComponent.writeValue (address-form.component.ts:32)
at setUpControl (shared.js:47)
at FormGroupDirective.addControl (form_group_directive.js:125)
at FormControlName._setUpControl (form_control_name.js:201)
at FormControlName.ngOnChanges (form_control_name.js:114)
at checkAndUpdateDirectiveInline (provider.js:249)
at checkAndUpdateNodeInline (view.js:472)
at checkAndUpdateNode (view.js:415)
at debugCheckAndUpdateNode (services.js:504)
at debugCheckDirectivesFn (services.js:445)
I think FormGroup instance should be injected to nested form component somehow...
Couple issues, on your AppComponent change your FormBuilder to:
this.form = fb.group({
name: 'foo bar',
address: fb.control({ //Not using FormGroup
city: 'baz',
town: 'qux',
})
});
On your AddressFormComponent you need to initialize your FormGroup like so:
form: FormGroup = new FormGroup({
city: new FormControl,
town: new FormControl
});
Here's the fork of your sample: https://stackblitz.com/edit/angular-np38bi
We (at work) encountered that issue and tried different things for months: How to properly deal with nested forms.
Indeed, ControlValueAccessor seems to be the way to go but we found it very verbose and it was quite long to build nested forms. As we're using that pattern a lot within our app, we've ended up spending some time to investigate and try to come up with a better solution. We called it ngx-sub-form and it's a repo available on NPM (+ source code on Github).
Basically, to create a sub form all you have to do is extends a class we provide and also pass your FormControls. That's it.
We've updated our codebase to use it and we're definitely happy about it so you may want to give a try and see how it goes for you :)
Everything is explained in the README on github.
PS: We also have a full demo running here https://cloudnc.github.io/ngx-sub-form

Ember could not get select value from template to component

I'm struggling with this. I would like to pass a select value from template to component.
Here is my template
<select name="bank" class="form-control" id="sel1" onchange={{action "updateValue" value="bank"}}>
{{#each banks as |bank|}}
<option value={{bank.id}}>{{bank.name}}</option>
{{/each}}
{{log bank.id}}
</select>
And here is my component
import Ember from 'ember';
export default Ember.Component.extend({
store: Ember.inject.service('store'),
banks: Ember.computed(function() {
return this.get('store').findAll('bank');
}),
didUpdate() {
const banques = this.get('banks');
const hash = [];
banques.forEach(function(banque) {
hash.push(banque.get('name'));
});
Ember.$(".typeahead_2").typeahead({ source: hash });
},
actions: {
expand: function() {
Ember.$('.custom-hide').attr('style', 'display: block');
Ember.$('.custom-display').attr('style', 'display: none');
},
updateValue(selectedValue) {
this.set('bank.id', selectedValue);
},
login() {
console.log(this.get('bank.id'));
}
}
});
And i've got this beautiful error : Property set failed: object in path "bank" could not be found or was destroyed.
Any idea ? Thanks
When you use value attribute then you need to specify correct property name to be retrieved from the first argument(event). in your case you just mentioned bank - which was not found in event object. that's the reason for that error.
onchange={{action "updateValue" value="target.value"}}
inside component
updateValue(selectedValue) {
this.set('bank.id', selectedValue);
},

Angular 2 : How to make POST call using form

I am completely new to Angular 2 and form concept. I am trying to POST form data to a POST API call. like this
POST API : http://localohot:8080/**********
Component :
user: any = {
id: null,
gender: null,
mstatus: null,
birthdate: null,
bloodgroup: null
}
userName: any = {
id: null,
personId: null,
displayName: '',
prefix: null,
givenName: null
}
userAddressJSON: any = {
id: null,
personId: null,
address1: null,
address2: null,
cityVillage: null
}
var form = new FormData();
form.append('userid', new Blob(['' + uid], { type: 'application/json' }));
form.append('user', new Blob([JSON.stringify(this.user)], { type: 'application/json' }));
form.append('userName', new Blob([JSON.stringify(this.userName)], { type: 'application/json' }));
form.append('userAddress', new Blob([JSON.stringify(this.userAddressJSON)], { type: 'application/json' }));
Here, I don't know how to make API call.
In our old application they used form data POST in jQuery. Now I am trying to do the same in Angular 2. When I do the form POST in old application they are sending like this
------WebKitFormBoundarybAWvwmP2VtRxvKA7
Content - Disposition: form - data; name = "userid"; filename = "blob"
Content - Type: application / json
------WebKitFormBoundarybAWvwmP2VtRxvKA7
Content - Disposition: form - data; name = "user"; filename = "blob"
Content - Type: application / json
------WebKitFormBoundarybAWvwmP2VtRxvKA7
Content - Disposition: form - data; name = "userName"; filename = "blob"
Content - Type: application / json
------WebKitFormBoundarybAWvwmP2VtRxvKA7
Content - Disposition: form - data; name = "userAddress"; filename = "blob"
Content - Type: application / json
Can any one help me how to do that form POST in Angular 2.
Here is how I currently make a POST call in my Angular 2 app, because it sounds like you could use a simple example of how to setup a form. Here is the Angular 2 documentation on How to Send Data to the Server.
For even more high level documentation on making AJAX requests in Angular 2 visit this URL.
in my app/app.module.ts
...
import { HttpModule } from '#angular/http';
...
#NgModule({
imports: [
...
HttpModule
...
],
declarations: [
...
],
providers: [ ... ],
bootstrap: [AppComponent],
})
export class AppModule { }
app/system-setup/system-setup.ts
export class SystemSetup {
system_setup_id: number;
name: string;
counter: number;
}
app/form-component/form.component.html (Notice the [(ngModel)], that is what binds the property of the object to the html input element)
<form class="form" (ngSubmit)="saveEdits()" #editSystemSetupForm="ngForm">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="theName" name="name" [(ngModel)]="selectedItem.name" #itemsName="ngModel" required minlength="3"/>
<div [hidden]="itemsName.valid || itemsName.pristine" class="alert alert-danger">Name is required! Min length of 3.</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="">Counter</label>
<input type="number" step=0.01 class="form-control" name="counter" [(ngModel)]="selectedItem.counter" />
</div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-8">
<button type="submit" class="btn btn-success" style="float: right; margin-left: 15px;" [disabled]="!editISystemSetupForm.form.valid" >Save</button>
<button type="button" class="btn btn-danger" style="float: right;" (click)="cancelEdits()">Cancel</button>
</div>
</div>
</form>
in my app/form-component/form.component.ts
import { Component, OnInit, Input, Output, EventEmitter } from '#angular/core';
import { Headers, RequestOptions, Http, Response } from '#angular/http';
import { SystemSetup } from '../system-setup/system-setup';
#Component({
selector: 'app-setup-form',
templateUrl: 'setup-form.component.html',
styleUrls: ['setup-form.component.css']
})
export class SetupFormComponent implements OnInit {
#Input() selectedItem: SystemSetup; // The object to be edited
#Output() finishedEditing = new EventEmitter<number>(); // When the POST is done send to the parent component the new id
// Inject the Http service into our component
constructor(private _http: Http) { }
// User is finished editing POST the object to the server to be saved
saveEdits(): void {
let body = JSON.stringify( this.selectedItem );
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this._http.post('http://localhost:8080/**********', body, options)
.map(this.extractData)
.do(
data => {
this.finishedEditing.emit(data.system_setup_id); // Send the parent component the id if the selectedItem
})
.toPromise()
.catch(this.handleError);
}
/**
* Gets the data out of the package from the AJAX call.
* #param {Response} res - AJAX response
* #returns SystemSetup - A json of the returned data
*/
extractData(res: Response): SystemSetup {
let body = res.json();
if (body === 'failed') {
body = {};
}
return body || {};
}
/**
* Handles the AJAX error if the call failed or exited with exception. Print out the error message.
* #param {any} error - An error json object with data about the error on it
* #returns Promise - A promise with the error message in it
*/
private handleError(error: any): Promise<void> {
// In a real world app, we might use a remote logging infrastructure
// We'd also dig deeper into the error to get a better message
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error(errMsg); // log to console instead
return Promise.reject(errMsg);
}
}
This URL is the link to the official Angular 2 documentation site, which is a very good reference for anything an Angular 2 developer could want.