Angular 5 Angular Material 2 - autocomplete with minLength - autocomplete

I added autocomplete field on my form in order to select a patient.
The patient data come from database. The problem is there are 40.000 patients
So i would like to load data after user has entered 3 characters minimum.
But i don't know how to check that and how to pass the input to the function (filter argument).
This is what i have done. for the moment the data are loaded when i click on the input field :
HTML :
<mat-form-field class="index-full-width">
<input
matInput
type="text"
[(ngModel)]="patientChoice"
placeholder="Patient"
aria-label="Patient"
[matAutocomplete]="autoPatient"
[formControl]="myControl"
(click)="getPatients()">
<mat-autocomplete (optionSelected)="selectPat()" #autoPatient="matAutocomplete" [displayWith]="displayFnPat">
<mat-option *ngFor="let patient of filteredPatients | async" [value]="patient">
<span>{{ patient.lastName }}</span>
<small>{{patient.firstName}}</small> |
<span>né(e) le {{ patient.dateNaissance }}</span> |
<small>IPP: {{patient.ipp}}</small>
</mat-option>
</mat-autocomplete>
</mat-form-field>
TS :
getPatients() {
let searchTerm = '*';
let success: any = {};
this.klinckServices.getPatients(searchTerm)
.then((webScriptdata) => {
success = webScriptdata;
this.listPatients = success.data.items ;
console.log(this.listPatients);
},
msg => {
alert(msg);
});
}
ngOnInit() {
this.filteredPatients = this.myControl.valueChanges.pipe(
startWith<string | Patient>(''),
map(patient => typeof patient === 'string' ? patient : patient.name),
map(name => name ? this.filterPatient(name) : this.listPatients.slice())
);
}
displayFnPat(patient: Patient): string | undefined {
return patient ? patient.name : undefined;
}
filterPatient(name: string) {
return this.listPatients.filter(patient =>
patient.name.toLowerCase().includes(name.toLowerCase()));
}

There's another way to do it and it is recommended here.
It's basically checking the length on your filter method.
filterPatient(name: string) {
if (name.length < 2) {
return [];
}
return this.listPatients.filter(patient =>
patient.name.toLowerCase().includes(name.toLowerCase()));
}

OK, solved by adding in HTML (keyup)="getPatients($event)" :
<input
matInput
type="text"
[(ngModel)]="patientChoice"
placeholder="Patient"
aria-label="Patient"
[matAutocomplete]="autoPatient"
[formControl]="myControl"
(keyup)="getPatients($event)"
>
And in TS file :
getPatients(event: any) {
let searchTerm = '';
searchTerm += event.target.value;
console.log(searchTerm);
if (searchTerm.length === 2) {
let success: any = {};
this.klinckServices.getPatients(searchTerm)
.then((webScriptdata) => {
success = webScriptdata;
this.listPatients = success.data.items;
console.log(this.listPatients);
},
msg => {
alert(msg);
});
}
}

Related

MVC app does not show selected values on a form reedition

I am building a Framework7 MVC app and found myself in a dead end alley. I have a form which I need to evaluate. This form contains selects. I am using localStorage to store the form values and everything works OK in that sense, I mean everything is stored correctly. ¿What is the issue? When I fill the form I answer some questions on textareas inputs, select inputs and inputs. everything goes fine until I try to reedit the form, then everything is display correctly on the form, including the score i got from my previous answers, but, the selects appears as if I have never touch them. Their previously selected value is stored but not display on the form. I have found that the issue is caused by the fact that I have set numerical values to the options values but what the form show is "yes" or "no". If I change the option values to "yes" or "no" then the form displays correctly but I need to set "5" or "0" because I need to evaluate the user's answers.
This is my code
The form
<li style="margin-top:-10px;">
<input style="visibility:hidden;height:1px;" value="0" name="choice" onchange="checkTotal()"/>
<input style="visibility:hidden;height:1px;" value="1" type="checkbox" name="choice" onchange="checkTotal()" checked="on">
</li>
<li><div class="item-content">1. ¿Sueles quejarte de sentirte mal?</div>
<div class="item-content">
<div class="item-inner">
<div class="item-input">
<select name="pr1" id="pr1" onchange="checkTotal()">
<option class="item-inner" value="5">No</option>
<option class="item-inner" value="0">Si</option>
</select>
</div>
</div>
</div>
<div class="item-content">En tal caso,</div>
<div class="item-content">
<div class="item-inner">
<div class="item-input">
<textarea class="resizable" id="pr1notes" placeholder="¿cuál es la causa?">{{model.pr1notes}}</textarea>
</div>
</div>
</div>
</li>
The functions on the editController
function init(query){
var protections = JSON.parse(localStorage.getItem("f7Protections"));
if (query && query.id) {
protection = new Protection(_.find(protections, { id: query.id }));
state.isNew = false;
}
else {
protection = new Protection({ isFavorite: query.isFavorite });
state.isNew = true;
}
View.render({ model: protection, bindings: bindings, state: state, doneCallback: saveProtection });
showSelectedValues();
}
function showSelectedValues(){
var fieldNames = protection.getSelectFields();
for (var i = 0, len = fieldNames.length; i < len; i++) {
var itemname = fieldNames[i];
var selectObj = document.getElementById(itemname);
if (selectObj!=null) {
var objOptions = selectObj.options;
var selIndex=0;
for (var j = 0, len2 = objOptions.length; j < len2; j++) {
if ((objOptions[j].label).localeCompare(protection[itemname])==0){
selIndex=j;
}
}
selectObj.options[selIndex].setAttribute("selected","selected");
}else{
}
}
}
and the model
Protection.prototype.setValues = function(inputValues, extras) {
for (var i = 0, len = inputValues.length; i < len; i++) {
var item = inputValues[i];
if (item.type === 'checkbox') {
this[item.id] = item.checked;
}
else {
this[item.id] = item.value;
}
}
for (var i = 0, len = extras[0].length; i < len; i++) {
var item = extras[0][i];
if((item.id).localeCompare("pr1notes")==0) {this[item.id] = item.value;}
}
console.log('starting loop for extras 3...');
for (var i = 0, len = extras[2].length; i < len; i++) {
var item = extras[2][i];
this[item.name] = item.value;
}
};
Protection.prototype.validate = function() {
var result = true;
if (_.isEmpty(this.prdate)
) {result = false;}
return result;
};
Protection.prototype.getSelectFields = function() {
return ['pr1'];
}
What should I change in order to keep my "5" or "0" values on the select options while the form options still show "yes" or "no" to the user just like this: <select name="pr1" id="pr1" onchange="checkTotal()"><option class="item-inner" value="5">No</option><option class="item-inner" value="0">Si</option></select>?
need anything else to help you understand the issue?
The simplest solution
function init(query){
var protections = JSON.parse(localStorage.getItem("f7Protections"));
if (query && query.id) {
protection = new Protection(_.find(protections, { id: query.id }));
state.isNew = false;
}
else {
protection = new Protection({ isFavorite: query.isFavorite });
state.isNew = true;
}
View.render({ model: protection, bindings: bindings, state: state, doneCallback: saveProtection });
showSelectedValues();
}
function showSelectedValues(){
var fieldNames = protection.getSelectFields();
for (var i = 0, len = fieldNames.length; i < len; i++) {
var itemname = fieldNames[i];
var selectObj = document.getElementById(itemname);
if (selectObj!=null) {
var objOptions = selectObj.options;
var selIndex=0;
for (var j = 0, len2 = objOptions.length; j < len2; j++) {
if ((objOptions[j].value).localeCompare(protection[itemname])==0){
selIndex=j;
}
}
selectObj.options[selIndex].setAttribute("selected","selected");
}else{
}
}
}
Just changed this line
if ((objOptions[j].label).localeCompare(protection[itemname])==0){
selIndex=j;
and changed .label for .value.

How can I had multiple chekbox on account creation on Prestashop 1.6

I would like to know more about my customers during their registration on my website. For this I just want to add on the account creation 5 checkoxes (he can choose more than one checkbox) and save it in the database and in personnal information in the account. Easy for me to add the checkboxes in the form, but I have no idea to do the rest.
I already add the checkboxes in the code, but I don't know what I need to change after. I modified only the authentication.tpl file.
This is my code to add the checkboxes in the form :
<p class="textarea">
<label for="other">{l s='Je suis :'}</label>
<div id="other_info">
<input class="checkboxx" type="checkbox" value="{if isset($smarty.post.other)}{$smarty.post.other}{/if}" id="other" name="Céréalier">
<span class="cerealier">Céréalier</span>
<input class="checkboxx" type="checkbox" value="{if isset($smarty.post.other)}{$smarty.post.other}{/if}" id="other" name="Éleveur">
<span class="eleveur">Éleveur</span>
<input class="checkboxx" type="checkbox" value="{if isset($smarty.post.other)}{$smarty.post.other}{/if}" id="other" name="Viticulteur">
<span class="viticulteur">Viticulteur</span>
<input class="checkboxx" type="checkbox" value="{if isset($smarty.post.other)}{$smarty.post.other}{/if}" id="other" name="Revendeur">
<span class="revendeur">Revendeur</span>
<input class="checkboxx" type="checkbox" value="{if isset($smarty.post.other)}{$smarty.post.other}{/if}" id="other" name="Autre">
<span class="autre">Autre</span><br>
</div>
</p>
I would like someone to help to realise this implemation on account creation with my multiple checkboxes.
This is my method processSubmitAccount() :
protected function processSubmitAccount()
{
Hook::exec('actionBeforeSubmitAccount');
$this->create_account = true;
if (Tools::isSubmit('submitAccount')) {
$this->context->smarty->assign('email_create', 1);
}
// New Guest customer
if (!Tools::getValue('is_new_customer', 1) && !Configuration::get('PS_GUEST_CHECKOUT_ENABLED')) {
$this->errors[] = Tools::displayError('You cannot create a guest account.');
}
if (!Tools::getValue('is_new_customer', 1)) {
$_POST['passwd'] = md5(time()._COOKIE_KEY_);
}
if ($guest_email = Tools::getValue('guest_email')) {
$_POST['email'] = $guest_email;
}
// Checked the user address in case he changed his email address
if (Validate::isEmail($email = Tools::getValue('email')) && !empty($email)) {
if (Customer::customerExists($email)) {
$this->errors[] = Tools::displayError('An account using this email address has already been registered.', false);
}
}
// Preparing customer
$customer = new Customer();
$other = Tools::getValue('other');
var_dump($other);
exit;
$customer->other = $other;
$lastnameAddress = Tools::getValue('lastname');
$firstnameAddress = Tools::getValue('firstname');
$_POST['lastname'] = Tools::getValue('customer_lastname', $lastnameAddress);
$_POST['firstname'] = Tools::getValue('customer_firstname', $firstnameAddress);
$addresses_types = array('address');
if (!Configuration::get('PS_ORDER_PROCESS_TYPE') && Configuration::get('PS_GUEST_CHECKOUT_ENABLED') && Tools::getValue('invoice_address')) {
$addresses_types[] = 'address_invoice';
}
$error_phone = false;
if (Configuration::get('PS_ONE_PHONE_AT_LEAST')) {
if (Tools::isSubmit('submitGuestAccount') || !Tools::getValue('is_new_customer')) {
if (!Tools::getValue('phone') && !Tools::getValue('phone_mobile')) {
$error_phone = true;
}
} elseif (((Configuration::get('PS_REGISTRATION_PROCESS_TYPE') && Configuration::get('PS_ORDER_PROCESS_TYPE'))
|| (Configuration::get('PS_ORDER_PROCESS_TYPE') && !Tools::getValue('email_create'))
|| (Configuration::get('PS_REGISTRATION_PROCESS_TYPE') && Tools::getValue('email_create')))
&& (!Tools::getValue('phone') && !Tools::getValue('phone_mobile'))) {
$error_phone = true;
}
}
if ($error_phone) {
$this->errors[] = Tools::displayError('You must register at least one phone number.');
}
$this->errors = array_unique(array_merge($this->errors, $customer->validateController()));
// Check the requires fields which are settings in the BO
$this->errors = $this->errors + $customer->validateFieldsRequiredDatabase();
if (!Configuration::get('PS_REGISTRATION_PROCESS_TYPE') && !$this->ajax && !Tools::isSubmit('submitGuestAccount')) {
if (!count($this->errors)) {
$this->processCustomerNewsletter($customer);
$customer->firstname = Tools::ucwords($customer->firstname);
$customer->birthday = (empty($_POST['years']) ? '' : (int)Tools::getValue('years').'-'.(int)Tools::getValue('months').'-'.(int)Tools::getValue('days'));
if (!Validate::isBirthDate($customer->birthday)) {
$this->errors[] = Tools::displayError('Invalid date of birth.');
}
// New Guest customer
$customer->is_guest = (Tools::isSubmit('is_new_customer') ? !Tools::getValue('is_new_customer', 1) : 0);
$customer->active = 1;
if (!count($this->errors)) {
if ($customer->add()) {
if (!$customer->is_guest) {
if (!$this->sendConfirmationMail($customer)) {
$this->errors[] = Tools::displayError('The email cannot be sent.');
}
}
$this->updateContext($customer);
$this->context->cart->update();
Hook::exec('actionCustomerAccountAdd', array(
'_POST' => $_POST,
'newCustomer' => $customer
));
if ($this->ajax) {
$return = array(
'hasError' => !empty($this->errors),
'errors' => $this->errors,
'isSaved' => true,
'id_customer' => (int)$this->context->cookie->id_customer,
'id_address_delivery' => $this->context->cart->id_address_delivery,
'id_address_invoice' => $this->context->cart->id_address_invoice,
'token' => Tools::getToken(false)
);
$this->ajaxDie(Tools::jsonEncode($return));
}
if (($back = Tools::getValue('back')) && $back == Tools::secureReferrer($back)) {
Tools::redirect(html_entity_decode($back));
}
// redirection: if cart is not empty : redirection to the cart
if (count($this->context->cart->getProducts(true)) > 0) {
$multi = (int)Tools::getValue('multi-shipping');
Tools::redirect('index.php?controller=order'.($multi ? '&multi-shipping='.$multi : ''));
}
// else : redirection to the account
else {
Tools::redirect('index.php?controller='.(($this->authRedirection !== false) ? urlencode($this->authRedirection) : 'my-account'));
}
} else {
$this->errors[] = Tools::displayError('An error occurred while creating your account.');
}
}
}
} else {
// if registration type is in one step, we save the address
$_POST['lastname'] = $lastnameAddress;
$_POST['firstname'] = $firstnameAddress;
$post_back = $_POST;
// Preparing addresses
foreach ($addresses_types as $addresses_type) {
$$addresses_type = new Address();
$$addresses_type->id_customer = 1;
if ($addresses_type == 'address_invoice') {
foreach ($_POST as $key => &$post) {
if ($tmp = Tools::getValue($key.'_invoice')) {
$post = $tmp;
}
}
}
$this->errors = array_unique(array_merge($this->errors, $$addresses_type->validateController()));
if ($addresses_type == 'address_invoice') {
$_POST = $post_back;
}
if (!($country = new Country($$addresses_type->id_country)) || !Validate::isLoadedObject($country)) {
$this->errors[] = Tools::displayError('Country cannot be loaded with address->id_country');
}
if (!$country->active) {
$this->errors[] = Tools::displayError('This country is not active.');
}
$postcode = $$addresses_type->postcode;
/* Check zip code format */
if ($country->zip_code_format && !$country->checkZipCode($postcode)) {
$this->errors[] = sprintf(Tools::displayError('The Zip/Postal code you\'ve entered is invalid. It must follow this format: %s'), str_replace('C', $country->iso_code, str_replace('N', '0', str_replace('L', 'A', $country->zip_code_format))));
} elseif (empty($postcode) && $country->need_zip_code) {
$this->errors[] = Tools::displayError('A Zip / Postal code is required.');
} elseif ($postcode && !Validate::isPostCode($postcode)) {
$this->errors[] = Tools::displayError('The Zip / Postal code is invalid.');
}
if ($country->need_identification_number && (!Tools::getValue('dni') || !Validate::isDniLite(Tools::getValue('dni')))) {
$this->errors[] = Tools::displayError('The identification number is incorrect or has already been used.');
} elseif (!$country->need_identification_number) {
$$addresses_type->dni = null;
}
if (Tools::isSubmit('submitAccount') || Tools::isSubmit('submitGuestAccount')) {
if (!($country = new Country($$addresses_type->id_country, Configuration::get('PS_LANG_DEFAULT'))) || !Validate::isLoadedObject($country)) {
$this->errors[] = Tools::displayError('Country is invalid');
}
}
$contains_state = isset($country) && is_object($country) ? (int)$country->contains_states: 0;
$id_state = isset($$addresses_type) && is_object($$addresses_type) ? (int)$$addresses_type->id_state: 0;
if ((Tools::isSubmit('submitAccount') || Tools::isSubmit('submitGuestAccount')) && $contains_state && !$id_state) {
$this->errors[] = Tools::displayError('This country requires you to choose a State.');
}
}
}
if (!#checkdate(Tools::getValue('months'), Tools::getValue('days'), Tools::getValue('years')) && !(Tools::getValue('months') == '' && Tools::getValue('days') == '' && Tools::getValue('years') == '')) {
$this->errors[] = Tools::displayError('Invalid date of birth');
}
if (!count($this->errors)) {
if (Customer::customerExists(Tools::getValue('email'))) {
$this->errors[] = Tools::displayError('An account using this email address has already been registered. Please enter a valid password or request a new one. ', false);
}
$this->processCustomerNewsletter($customer);
$customer->birthday = (empty($_POST['years']) ? '' : (int)Tools::getValue('years').'-'.(int)Tools::getValue('months').'-'.(int)Tools::getValue('days'));
if (!Validate::isBirthDate($customer->birthday)) {
$this->errors[] = Tools::displayError('Invalid date of birth');
}
if (!count($this->errors)) {
$customer->active = 1;
// New Guest customer
if (Tools::isSubmit('is_new_customer')) {
$customer->is_guest = !Tools::getValue('is_new_customer', 1);
} else {
$customer->is_guest = 0;
}
if (!$customer->add()) {
$this->errors[] = Tools::displayError('An error occurred while creating your account.');
} else {
foreach ($addresses_types as $addresses_type) {
$$addresses_type->id_customer = (int)$customer->id;
if ($addresses_type == 'address_invoice') {
foreach ($_POST as $key => &$post) {
if ($tmp = Tools::getValue($key.'_invoice')) {
$post = $tmp;
}
}
}
$this->errors = array_unique(array_merge($this->errors, $$addresses_type->validateController()));
if ($addresses_type == 'address_invoice') {
$_POST = $post_back;
}
if (!count($this->errors) && (Configuration::get('PS_REGISTRATION_PROCESS_TYPE') || $this->ajax || Tools::isSubmit('submitGuestAccount')) && !$$addresses_type->add()) {
$this->errors[] = Tools::displayError('An error occurred while creating your address.');
}
}
if (!count($this->errors)) {
if (!$customer->is_guest) {
$this->context->customer = $customer;
$customer->cleanGroups();
// we add the guest customer in the default customer group
$customer->addGroups(array((int)Configuration::get('PS_CUSTOMER_GROUP')));
if (!$this->sendConfirmationMail($customer)) {
$this->errors[] = Tools::displayError('The email cannot be sent.');
}
} else {
$customer->cleanGroups();
// we add the guest customer in the guest customer group
$customer->addGroups(array((int)Configuration::get('PS_GUEST_GROUP')));
}
$this->updateContext($customer);
$this->context->cart->id_address_delivery = (int)Address::getFirstCustomerAddressId((int)$customer->id);
$this->context->cart->id_address_invoice = (int)Address::getFirstCustomerAddressId((int)$customer->id);
if (isset($address_invoice) && Validate::isLoadedObject($address_invoice)) {
$this->context->cart->id_address_invoice = (int)$address_invoice->id;
}
if ($this->ajax && Configuration::get('PS_ORDER_PROCESS_TYPE')) {
$delivery_option = array((int)$this->context->cart->id_address_delivery => (int)$this->context->cart->id_carrier.',');
$this->context->cart->setDeliveryOption($delivery_option);
}
// If a logged guest logs in as a customer, the cart secure key was already set and needs to be updated
$this->context->cart->update();
// Avoid articles without delivery address on the cart
$this->context->cart->autosetProductAddress();
Hook::exec('actionCustomerAccountAdd', array(
'_POST' => $_POST,
'newCustomer' => $customer
));
if ($this->ajax) {
$return = array(
'hasError' => !empty($this->errors),
'errors' => $this->errors,
'isSaved' => true,
'id_customer' => (int)$this->context->cookie->id_customer,
'id_address_delivery' => $this->context->cart->id_address_delivery,
'id_address_invoice' => $this->context->cart->id_address_invoice,
'token' => Tools::getToken(false)
);
$this->ajaxDie(Tools::jsonEncode($return));
}
// if registration type is in two steps, we redirect to register address
if (!Configuration::get('PS_REGISTRATION_PROCESS_TYPE') && !$this->ajax && !Tools::isSubmit('submitGuestAccount')) {
Tools::redirect('index.php?controller=address');
}
if (($back = Tools::getValue('back')) && $back == Tools::secureReferrer($back)) {
Tools::redirect(html_entity_decode($back));
}
// redirection: if cart is not empty : redirection to the cart
if (count($this->context->cart->getProducts(true)) > 0) {
Tools::redirect('index.php?controller=order'.($multi = (int)Tools::getValue('multi-shipping') ? '&multi-shipping='.$multi : ''));
}
// else : redirection to the account
else {
Tools::redirect('index.php?controller='.(($this->authRedirection !== false) ? urlencode($this->authRedirection) : 'my-account'));
}
}
}
}
}
if (count($this->errors)) {
//for retro compatibility to display guest account creation form on authentication page
if (Tools::getValue('submitGuestAccount')) {
$_GET['display_guest_checkout'] = 1;
}
if (!Tools::getValue('is_new_customer')) {
unset($_POST['passwd']);
}
if ($this->ajax) {
$return = array(
'hasError' => !empty($this->errors),
'errors' => $this->errors,
'isSaved' => false,
'id_customer' => 0
);
$this->ajaxDie(Tools::jsonEncode($return));
}
$this->context->smarty->assign('account_error', $this->errors);
}
}
First, you need to know that checkbox need same name but different values. so i think you more need radio buttons than checkboxes.
anyway, to add field to registration form, you need just some modifications (backup bdd and code first) :
modify HTML
modify Database structure
modify PHP
1) Template
<p class="textarea">
<label for="typeagri">{l s='Je suis :'}</label>
<div id="typeagri_info">
<span class="cerealier">Céréalier</span>
<input class="checkboxx" type="checkbox" value="Céréalier" id="typeagri1" name="typeagri[]">
<span class="eleveur">Éleveur</span>
<input class="checkboxx" type="checkbox" value="Éleveur" id="typeagri2" name="typeagri[]">
<span class="viticulteur">Viticulteur</span>
<input class="checkboxx" type="checkbox" value="Viticulteur" id="typeagri3" name="typeagri[]">
<span class="revendeur">Revendeur</span>
<input class="checkboxx" type="checkbox" value="Revendeur" id="typeagri4" name="typeagri[]">
<span class="autre">Autre</span>
<input class="checkboxx" type="checkbox" value="Autre" id="typeagri5" name="typeagri[]">
</div>
</p>
2) Database change (execute SQL in phpmyadmin)
ALTER TABLE ps_customer
ADD COLUMN typeagri VARCHAR(250)
3) PHP changes
in /controllers/front/AuthController.php
find "// if registration type is in one step, we save the address"
and after add that code :
$typeagris ='';
foreach(Tools::getValue('typeagri') as $t) {
$typeagris .= $t.',';
}
$customer->typeagri = $typeagris;
in /classes/Customer.php
find "public $firstname;" and after add that code :
/** #var string typeagri */
public $typeagri;
find "'passwd' => array('type' => self::TYPE_STRING, 'validate' => 'isPasswd', 'required' => true, 'size' => 32)," and after add that code :
'typeagri' => array('type' => self::TYPE_STRING),
empty cache and test your modifications.
And for the identity form :
in indentity.tpl
After :
<div class="form-group">
<label for="website">{l s='Website'}</label>
<input type="text" class="form-control" id="website" name="website" value="{if isset($smarty.post.website)}{$smarty.post.website}{/if}" />
</div>
add :
<div class="form-group">
<p class="textarea">
<label for="typeagri">{l s='Je suis :'}</label>
<!--
{assign var="typeagris" value=","|explode:$smarty.post.typeagri}
{section name=i loop=$typeagris}
{$typeagris[i]}<br>
{/section}
-->
<div id="typeagri_info">
<input {if $smarty.post.typeagri|stristr:"alier"} checked=checked{/if} class="checkboxx" type="checkbox" value="Céréalier" id="typeagri1" name="typeagri[]"> <span class="cerealier">Céréalier</span>
<input {if $smarty.post.typeagri|stristr:"leveur"} checked=checked{/if} class="checkboxx" type="checkbox" value="Éleveur" id="typeagri2" name="typeagri[]"> <span class="eleveur">Éleveur</span>
<input {if $smarty.post.typeagri|stristr:"iticulteur"} checked=checked{/if} class="checkboxx" type="checkbox" value="Viticulteur" id="typeagri3" name="typeagri[]"> <span class="viticulteur">Viticulteur</span>
<input {if $smarty.post.typeagri|stristr:"evendeur"} checked=checked{/if} class="checkboxx" type="checkbox" value="Revendeur" id="typeagri4" name="typeagri[]"> <span class="revendeur">Revendeur</span>
<input {if $smarty.post.typeagri|stristr:"utre"}checked=checked{/if} class="checkboxx" type="checkbox" value="Autre" id="typeagri5" name="typeagri[]"> <span class="autre">Autre</span>
</div>
</p>
</div>
in IdentityController.php :
Before :
return $this->customer;
Add :
$typeagris ='';
foreach(Tools::getValue('typeagri') as $t) {
$typeagris .= $t.',';
}
$customer->typeagri = $typeagris;
If it works, you can now do the same with override (please take a look at http://doc.prestashop.com/pages/viewpage.action?pageId=51184698 )
Overriding is very important, to not mix native source code and your modifications.
Good luck

Filter list based on more than one field

I'm iterating a list of jobs and there's a search implemented on this list.
Search is working but now it only filters list based on one field.
Here's my list:
<ion-card *ngFor="let job of allJobs | search : searchTerm">
<ion-grid>
<ion-row>
<ion-col>
<div>
<span> {{job.day | uppercase}}</span>
<span> {{job.month | uppercase}}</span>
</div>
</ion-col>
<ion-col>
<div>
<span>{{job.time}}</span>
<span>{{job.name}}</span>
</div>
</ion-col>
</ion-row>
</ion-grid>
</ion-card>
I made a pipe for implementing search. Here's the code for it.
transform(items: any[], terms: string): any[] {
if(!items) return [];
if(!terms) return items;
terms = terms.toLowerCase();
return items.filter( it => {
return it.name.toLowerCase().includes(terms); // only filter name
});
}
Now the list gets filtered only based on the name field. I wanna filter the list based on day, month and time as well.
Can anyone tell me how to make this happen?
Sample Data for Jobs. Jobs is an array of objects
[
{
"id":10,
"day":"Monday",
"month":"June",
"time":"10",
"name":"John",
"email":"john#gmail.com"
},
{
"id":11,
"day":"Tuesday",
"month":"May",
"time":"12",
"name":"Jane",
"email":"jane#gmail.com"
},
{
"id":12,
"day":"Friday",
"month":"June",
"time":"16",
"name":"",
"email":"john#gmail.com"
},
{
"id":13,
"day":"Tuesday",
"month":"August",
"time":"21",
"name":"",
"email":"kevin#gmail.com"
},
{
"id":14,
"day":"Saturday",
"month":"December",
"time":"12",
"name":"Sam",
"email":"sam#gmail.com"
},
]
And searchTerm is just a string.
As you can see, there are more fields in the sample data than the one displayed in the HTML but I'm trying only to search for the fields that are displayed in the HTML. Some fields can have null values (for eg. name in the sample data has two null values)
I tried the solutions already provided but none of them are working for my requirement.
P.S: Read somewhere that pipes are not the best option to do functionality like this. I'm ready to implement this logic in the class as well.
Try combining your includes with the logical or-operator (||):
transform(items: any[], terms: string): any[] {
if (!items) return [];
if (!terms) return items;
terms = terms.toLowerCase();
return items.filter(it => {
return it.name.toLowerCase().includes(terms) ||
it.day.toLowerCase().includes(terms) ||
it.month.toLowerCase().includes(terms) ||
it.time.toLowerCase().includes(terms)
});
}
This statement will return true if any of the includes returns true. So basically any item which name, day, month or time contains the searchterm will be returned by the pipe.
This solution assumes that name, day, month and time are not null or undefined. But I'm assuming that is okay as your sample data suggests null values will be empty strings(""). If my assumption is not correct you'll have to check if the values are assigned, before accessing them.
Try this code.. it's pretty simple.
transform(items: any[], terms: string): any[] {
if (!items) return [];
if (!terms) return items;
terms = terms.toLowerCase();
terms = terms.trim();
return items.filter(it => {
if (it.day) {
return it.day.toLowerCase().includes(terms);
}
if (it.month) {
return it.month.toLowerCase().includes(terms);
}
if (it.time) {
return it.time.toLowerCase().includes(terms);
}
if (it.name) {
return it.name.toLowerCase().includes(terms);
}
});
}
If your JSON has null values, you can replace it with an empty string using the following code:
items = JSON.parse(JSON.stringify(items).replace(/null/g, '""'));
This dont work because the includes dont test for multiple term cases. You didnt say whats inside the items Array but if it is a String you could do this:
transform(items: any[], terms: string): any[] {
if(!items) return [];
if(!terms) return items;
terms = terms.toLowerCase();
return items.filter( it => {
//if it is something like "Programmer 07 November 12:00PM"
var informations = it.split(' '); //["Programmer", "07" ,"November" ,"12:00PM"]
var termArray = terms.split(' ');
var rightResult = true;
for (var index in termArray) {
if !(informations.include(termArray[index])) {
rightResult = false;
}
return rightResult;
});
}
Inside your transform method of your search pipe, apply filters on all the fields you want to apply filter on. Following will search for all keys in the object:
transform(items: any[], terms: string): any[] {
if(!items) return [];
if(!terms) return items;
terms = terms.toLowerCase();
return items.filter( it => {
return keys(it).reduce((prev, key) => {
return prev || key.toLowerCase().includes(term);
}, false);
});
}
If keys or Object.keys are not working, use the following code instead of reduce function:
...
let bInclude = false;
for(let key in it){
bInclude = bInclude || key.toLowerCase().includes(term);
}
return bInclude;
...
filterItems(param: any): void {
let val: string = param;
if (val) {
if (val.trim() !== '') {
this.filterItemsList = this.items.filter((data) => {
console.log(data.category);
return data.category.toLowerCase().indexOf(val.toLowerCase()) > -1
|| data.products.some(product => product.code.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
}
}
}
it's working perfect

reactive forms: use one validator for multiple fields

I'm using angular 2 reactive forms and made a validator for a date of birth field. The validator is working, but it turns out the date of birth field is split into three new field: year, month, day. They all have their own validators. My question is, how can I change my code so my original date of birth validator works on three fields.
my original validator that checks one field.
input(2000/12/12) is valid
export function dobValidator(control) {
const val = control.value;
const dobPattern = /^\d{4}\/\d{2}\/\d{2}$/ ;
const comp = val.split('/');
const y = parseInt(comp[0], 10);
const m = parseInt(comp[1], 10);
const d = parseInt(comp[2], 10);
const jsMonth = m - 1;
const date = new Date(y, jsMonth, d);
const isStringValid = dobPattern.test(control.value);
const isDateValid = (date.getFullYear() === y && date.getMonth() === jsMonth && date.getDate() === d);
return (isStringValid && isDateValid) ? null : { invalidDob: ('Date of birth not valid') };
};
new html with 3 fields
year has a validator that checks the year
day has a validator that checks if the input is between 1 and 31
month has a validator that checks if the input is between 1 and 12.
I want to combine the above input of the three field into a new string and use my original date of birth validator.
<label>Date of birth :</label>
<div>
<div class="col-xs-1">
<input required type="text" formControlName="day" class="form-control" placeholder="dd" id="day"/>
<p *ngIf="form.controls.day.dirty && form.controls.day.errors">{{ form.controls.day.errors.invalidDay }}</p>
</div>
<div class="col-xs-1">
<input required type="text" formControlName="month" class="form-control" placeholder="mm" id="month"/>
<p *ngIf="form.controls.month.dirty && form.controls.month.errors">{{ form.controls.month.errors.invalidMonth }}</p>
</div>
<div class="col-xs-2">
<input required type="text" formControlName="year" class="form-control" placeholder="yyyy" id="year"/>
<p *ngIf="form.controls.year.dirty && form.controls.year.errors">{{ form.controls.year.errors.invalidYear }}</p>
</div>
</div>
<div>
<button type="submit" [disabled]="form.invalid">Submit</button>
</di>
I have created a validator for comparing two dates (their format is NgbDateStruct - as used in ng-bootstrap package's datepickers)
import { Directive, forwardRef, Attribute } from '#angular/core';
import { Validator, AbstractControl, NG_VALIDATORS, ValidatorFn } from '#angular/forms';
import { NgbDateStruct } from "#ng-bootstrap/ng-bootstrap";
import { toDate } from "../helpers/toDate";
export function dateCompareValidator(compareToControl: string, compareToValue: NgbDateStruct, compareType: string, reverse: boolean, errorName: string = 'dateCompare'): ValidatorFn {
return (c: AbstractControl): { [key: string]: any } => {
let compare = function (self: Date, compareTo: Date): any {
console.log('comparing ', compareType.toLowerCase());
console.log(self);
console.log(compareTo);
if (compareType.toLowerCase() === 'ge') {
if (self >= compareTo) {
return true;
} else {
return false;
}
} else if (compareType.toLowerCase() === 'le') {
if (self <= compareTo) {
return true;
} else {
return false;
}
}
return false;
};
// self value
let v = c.value;
// compare vlaue
let compareValue: Date;
let e;
if (compareToValue) {
compareValue = toDate(compareToValue);
} else {
e = c.root.get(compareToControl);
if (e) {
compareValue = toDate(e.value);
}
else {
// OTHER CONTROL NOT FOUND YET
return null;
}
}
let controlToValidate: AbstractControl = reverse ? e : c;
// validate and set result
let error = null;
let result = compare(toDate(c.value), compareValue);
if (result === true) {
console.log('clearing errors', compareToControl);
if (controlToValidate.errors) {
delete controlToValidate.errors[errorName];
if (!Object.keys(controlToValidate.errors).length) {
controlToValidate.setErrors(null);
}
}
else {
console.log('errors property not found in control', controlToValidate);
}
} else {
error = {};
error[errorName] = false;
controlToValidate.setErrors(error);
console.log(controlToValidate.errors);
console.log(controlToValidate.value);
console.log('Error Control', controlToValidate);
console.log('returning errors');
}
return reverse ? null : error;
}
}
Couldn't manage to modify much lot to best describe here as an answer but I believe you would get your query answered in this validator function code.
Note:
Function toDate() used in the code is a small function I created to convert NgbDateStruct into a javascript date object so that comparing dates can get easier. Here goes its implementation:
import { NgbDateStruct } from "#ng-bootstrap/ng-bootstrap"
export function toDate(ngbDate: NgbDateStruct): Date {
return ngbDate != null ? new Date(Date.UTC(ngbDate.year, ngbDate.month, ngbDate.day)) : null;
}

Extending Dynamic-forms from angular2 cookbook to be able to have arrays

I have tried to extend the Dynamic-Forms app from angular 2 cookbook so I can have an array of multiple fields. I have been able to show the fields, but when I'm filling the form, I'm getting just the last element of the array filled.
Hier is my plunker with that state of the app:
//question-array.ts
import { QuestionBase } from './question-base';
export class ArrayQuestion extends QuestionBase<string> {
controlType = 'array';
options:{childe:FormElement<string>}[] = [];
constructor(options:{} = {}){
super(options);
this.options = options['options'] || [];
}
}
//question-control.service.ts
...
toFormGroup(formelements: QuestionBase<any>[] ) {
let group:any = {};
formelements.forEach(element => {
console.log("+element",element);
if(element.controlType === "array"){
let arr:any[] = [];
let locobj = {};
element["options"].forEach((option:any) => {
option["element"].forEach((e:any) =>{
locobj[e.key] = new FormControl(e.value || '');
});
arr.push(new FormGroup(locobj))
});
group[element.key] = new FormArray(arr);
}else{
group[element.key] = element.required ? new FormControl(element.value || '', Validators.required)
: new FormControl(element.value || '');
}
});
return new FormGroup(group);
}
//dynamic-form-question.component.html
...
<div *ngSwitchCase="'array'" [formArrayName]="question.key">
<div *ngFor="let item of question.options; let i=index" [formGroupName]="i" >
<div *ngFor="let element of item.element">
<div *ngIf="element.controlType === 'textbox'" >
<label>{{element.label}}</label>
<input [formControlName]="element.key" [id]="element.key" [type]="element.type" />
</div>
<div *ngIf="element.controlType === 'dropdown'" >
<label>{{item.label}}</label>
<select [id]="element.key" [formControlName]="element.key">
<option *ngFor="let opt of element.options" [value]="opt.key">{{opt.value}}</option>
</select>
</div>
</div>
</div>
</div>
...
http://plnkr.co/edit/DZ05fO
Best regard,
Shefki
I found the bug, the problem was that I was passing the same reference in the form group her is what i changed:
//question-control.service.ts
toFormGroup(formelements: QuestionBase[] ) {
let group:any = {};
formelements.forEach(element => {
if(element.controlType === "array"){
let arr:any[] = [];
let locobj = {};
element["options"].forEach((option:any) => {
option["element"].forEach((e:any) =>{
locobj[e.key] = e.value || '';
});
arr.push(new FormGroup(this.getFormControlObject(locobj)));
});
group[element.key] = new FormArray(arr);
}else{
group[element.key] = element.required ? new FormControl(element.value || '', Validators.required)
: new FormControl(element.value || '');
}
});
return new FormGroup(group);
}
private getFormControlObject(keys){
let retobj = {};
Object.keys(keys).forEach(function(key) {
retobj[key] = new FormControl(keys[key]);
});
return retobj;
}
Hier is a working plunker
http://plnkr.co/edit/4IMKdLKE51n41jzYY8sU