I have a dropdown where I get some json data. I am doing this in angular. So here I have a List named options where the data is in json format inside. So I have to display the name field at dropdown So my task here is to do a autocomplete search on this dropdown. I have attached my stackblitz link here.
You need to fix your filter method as:
private _filter(value: any): any {
const filterValue = value.toLowerCase();
return this.options.filter(option =>
option.name.toLowerCase().includes(filterValue)
);
}
Here is the demo code
You are comparing an object with the filter value.
Your filter callback function should be like this.
option => option.name.toLowerCase().includes(filterValue)
It's solved your problem.
return this.options.filter(option => option.name.toLowerCase().indexOf(filterValue) === 0);
Related
onMounted(() => {
productService.value
.getProducts()
.then((data) => (products.value = data));
console.log((products))
});
When I print products with console.log, here what I have.
capture of the console
I see that the data I want are in RawValue but I don't know how to access them.
I tried Object.values(products) or just console.log(products._rawValue) or console.log(products.rawValue) it print undefined.
Do you know what function call ?
Thanks
There are 2 issues
#1 - you're using console.log(products) which shows you the reactive object, what you need instead is console.log(products.value) which will only show the value, which should match the content of data.produtcs
#2 - you might find that 👆 now shows an empty result. The reason that's happening is that you're calling the console log after the async function, but before it finishes, so you're calling it before it has a chance to update. To fix that, you can log as part of the async function
onMounted(() => {
productService.value
.getProducts()
.then((data) => {
products.value = data;
console.log(products.value);
})
});
If you're using the products inside a template, you don't need to worry about what's before or after the async function since it will re-render the component on change.
Also, you probably don't need to define productService as a ref, the class is likely not something that needs to be reactive, so you can just do simple assignment and then skip the .value to call getProducts
with axios what I do is take out the data with response.data you could try
onMounted(() => {
productService.value.getProducts().then((response) => (
products = response.data
));
console.log(products.length);
});
i'm creating quiz app using angular and i have code like this
ngOnInit() {
this.myForm = this.fb.group({
lessonCode: "test",
answer: this.fb.array([])
});
}
onChange(email: string, code: string, isChecked: boolean) {
const emailFormArray = <FormArray>this.myForm.controls.answer;
if (isChecked) {
let array = new FormGroup({
questionCode: new FormControl(email),
emailCode: new FormArray([
new FormControl(code)
]),
});
emailFormArray.push(array);
} else {
let index = emailFormArray.controls.findIndex(x => x.value == email);
emailFormArray.removeAt(index);
}
}
which producing array like this
Form values: {
"lessonCode": "test",
"answer": [
{
"questionCode": "pertanyaan2",
"emailCode": [
"option2"
]
},
{
"questionCode": "pertanyaan2",
"emailCode": [
"option1"
]
}
]
}
but what i'm actually needed is like this
Form values: {
"lessonCode": "test",
"answer": [
{
"questionCode": "pertanyaan2",
"emailCode": {
"option2",
"option1"
}
}
]
}
how can i achieve that? any thoughts would be very helpful
i have minimal reproduce here https://stackblitz.com/edit/angular-ca1jin?file=src%2Fapp%2Fapp.component.ts
I suggested another aproach
If we create a formGroup like
this.myForm = this.fb.group({
lessonCode: "test",
answer: this.fb.array(this.users.map(x=>this.fb.group({
questionCode:x.code,
email:[[]]
})))
});
See that answer is a FormArray of FormGroup, each FormGroup has two FormsControl, questionCode and email, that is still a FormControl (but store an array). You need don't confussed with a FormArray. A FormControl can store an array, an object, an string, a number, etc.. And it's no so strange store an array, e.g. the mat-select multiple store an array too
As always we work with formArrays we declare a getter to manage in the .html
get answers()
{
return this.myForm.get('answer') as FormArray
}
Well, the form is a bit complex
<form [formGroup]="myForm">
<div formArrayName="answer">
<div *ngFor="let group of answers.controls;let i=index">
<p>{{users[i].code}}</p>
<div *ngFor="let user of users[i].email">
<input #check type="checkbox"
[value]="answers.at(i).value.email.indexOf(user.code)>=0"
(change)="onChange(i,user.code,check.checked)" >{{user.code}}<br>
</div>
</div>
</div>
</form>
See how we use [value]="answers.at(i).value.email.indexOf(user.code)>=0" Really it's not necesary if our "email" control is at first empy, but it possible we want in a future use this form to show the result, and our "eamil" can value, e.g. "[option1]"
Another thing to take account is that I use a template reference variable #check and send to the function OnChange check.checked -so we received in the function a boolean-
Our function OnChange get more simple
onChange(index:number, code: string, isChecked: boolean) {
const control=this.answers.at(index).get('email')
if (isChecked && control.value.indexOf(code)<0)
control.setValue([...control.value,code]
.sort((a:string,b:string)=>
this.users[index].email.findIndex(x=>x.code==a)>
this.users[index].email.findIndex(x=>x.code==b)?1:-1)
)
if (!isChecked && control.value.indexOf(code)>=0)
control.setValue(control.value.filter(x=>x!=code))
}
I like check if exist or not before remove/add the element
See that we need "sort" the response when the check is true -else we received the response, e.g. [option2,option1] -If our requeriments don't required we can remove the sort-
The stackblitz
What you need to do is to add emailCode as FormArray instead of FormControl, this way you will be able to check whether the questionCode already exists, and if yes, you can append to emailCode the option you checked.
The only things to change are on your onChange method
First you array variable, you need to add FormArray instead of FormControl
let array = new FormGroup({
questionCode: new FormControl(email),
emailCode: new FormArray([])
});
Then create a FormControl for your checked option
let codeOption = new FormControl(code)
And finally, in your if condition, check if the questionCode already exist to just append your formControl to it, or to create a new object.
if (isChecked) {
if (emailFormArray.controls.some(obj => obj.get('questionCode').value == email)){
(<FormArray>emailFormArray.controls.find(obj => obj.get('questionCode').value == email).get('emailCode')).push(codeOption);
}else{
(<FormArray>array.get('emailCode')).push(codeOption)
emailFormArray.push(array)
}
}
To be more clear I have modified your stackblitz to fit with your needs
I have not modified the else condition to remove the options on your FormArray but you just need to copy the if condition to get the index of the code element on your FormArray of emailCode.
You can make a function that traverses every answer and returns an object in your desired schema.
I have a Validators.pattern for a field, and that's the only validation I have on my form.
Normal usage is working. It validates the field properly however the issue occurs when you try to copy and paste.
If you copy and paste on the field repeatedly on the field, it is like the validity of the field is being toggled( submit button is disabled if form is invalid )
Issue also occurs when I populate a the data from other source like search or auto-suggest.
buildForm(obj) {
this.form = this.fb.group({
field: [obj['field'] || '', Validators.pattern(/MY_REG_EX_HERE/g)],
id: [obj['id'] || ''],
});
}
I am not really sure about the main cause of the issue but as a workaround, I created custom validator with same REGEX. I will post it here and might help someone.
import { AbstractControl, ValidationErrors, ValidatorFn } from '#angular/forms';
export function customValidator(control: AbstractControl) {
if (control.value !== '') {
const isValid = (/MY_REG_EX_HERE/g).test(control.value)
return isValid ? null : { customValidator: true };
} else {
return null;
}
}
I had a similar problem. I studied it in detail and found out the reason. Like me, you are using the /g modifier. which has a side effect if the regex is assigned to a variable. This modifier indicates the continuation of the search in the string. To understand the "unexpected" behavior, take a look at the screenshot.
You can find out more information here
So I am still kind of a novice at Angular 2. My API call returns an object with several arrays and objects within it.
This is the JSON object I receive when i make the get request
{"report":[{"customer_name":"kaminto" ,
"customer_address":"Second","tel_no":"Second","id":"15","order_no":"RC13",
"total_amount":"28000","amount_paid":"30000","balance":"-2000",
"sale_date":"2017-08-15" ,"customer_id":"21"},"}], "message":"success" ,
"totalSales":[{"amount_paid":"1174300"}]}
I want to output the customer_name and address but they are within the Report array.
Using observables, How can I save this information into objects that i can bind to the html.
Please help.
[SOLVED]
I know this is embarrassing, but i solved it. I just had to add the string type and array brackets to the interface report variable.
export interface ISalesReport{
report:string[];
message:string;
totalSales:string[];
}
I don't know exactly why, but after i did this, it worked.
You get that object from Observable? Yes, it is not necessary if you only need value of two properties. Something like this should help:
customer_name;
customer_address;
yourObservable.map(allReports => allReports.map(report => report
.map(val => { this.customer_name = val.customer_name;
this.customer_address = val.customer_address } ));
Suppose you called your service in your component that returns an observable of the GET call.
In your Service,
getCall() {
return this.http.get(...).map((res) => res.json());
}
In your Component, (say you assign to a property),
responseObj: Observable<any>;
// say you receive values in ngOnInit(),
ngOnInit() {
this.responseObj = this.service.getCall();
}
In your html, use the async pipe for eternally binding it to the observable,
<div [innerHTML]="(responseObj | async)?.report[0].customer_name"></div>
<div [innerHTML]="(responseObj | async)?.report[0].customer_address"></div>
Hope it helps.
Hi I am trying to implement a autocomplete field using Zend Jquery. I followed a tutorial to grab the data from an array and I have extended the code to access the data from my mysql table.
IndexController.php
$this->view->autocompleteElement = new ZendX_JQuery_Form_Element_AutoComplete('ac');
$this->view->autocompleteElement->setLabel('Autocomplete');
$this->view->autocompleteElement->setJQueryParam('source', '/index/city');
This calls the cityAction()
public function cityAction()
{
$results = Application_Model_City::search($this->_getParam('term'));
$this->_helper->json(array_values($results));
}
I then call the Model City
public static function search($term)
{
$region = new Application_Model_DbTable_Regions();
$results = $region->getRegion($term);
return $results;
}
And finally the Regions db model
public function getRegion($term)
{
$select = $this->select()->from($this,'City')
->where('City LIKE ? ',$term.'%');
return $this->fetchAll($select)->toArray();
}
Now when I go the autocomplete field it shows the results but as UNDEFINED , I think its something to do the way I am send the data back to the json helper.
I used firebug and I can see the data is been pulled in the following format.
[{"City":"London"},{"City":"Londonderry"},{"City":"Longfield"},{"City":"Longhope"},{"City":"Longniddry"}]
I think this format is incorrect, please any body dealt with this before?
Cheers
J
The ZendX_JQuery_Form_Element_AutoComplete element is a proxy to the AutoComplete View Helper, which is a proxy to the jQuery UI Autocomplete widget.
If you read the overview on the jQuery UI Autocomplete page, you will note:
The local data can be a simple Array of Strings, or it contains Objects for each item in the array, with either a label or value property or both. The label property is displayed in the suggestion menu. The value will be inserted into the input element after the user selected something from the menu. If just one property is specified, it will be used for both, eg. if you provide only value-properties, the value will also be used as the label.
When a String is used, the Autocomplete plugin expects that string to point to a URL resource that will return JSON data. It can be on the same host or on a different one (must provide JSONP). The request parameter "term" gets added to that URL. The data itself can be in the same format as the local data described above.
So, the JSON you are returning to the autocomplete should be structured more like:
[{"label":"London","value":"London"},{"label":"Londonderry","value":"Londonderry"},{"label":"Longfield","value":"Longfield"}]
Good luck!
Fixed the problem afters hours of pain!
I modified the below code where it accesses the data
public function getRegion($term)
{
$select = $this->select()->from($this,'City')
->where('City LIKE ? ',$term.'%');
return $this->fetchAll($select)->toArray();
}
I added a line of SQL City AS Value
public function getRegion($term)
{
$select = $this->select()->from($this,'City AS value')
->where('City LIKE ? ',$term.'%');
return $this->fetchAll($select)->toArray();
}
This seems to have worked!
Cheers
J