DropDown contents depending on multiple other DropDown values - atk4

I'm again. I've seen many threads which asking, how to create Dropdowns with content depending of a other Dropdown value. These logic works also for me. But now I have the problem, that the content of a Dropdown depends of the selection/value of 2 other Dropdowns. The code for depending on one Dropdown would looks like this:
$form = $crud->form;
$dd1 = $form->addField('dropdown', 'color', 'Color');
$dd1->setValueList(array('1' => 'white', '2' => 'black'));
$dd1->setEmptyText('all');
$dd2 = $form->addField('dropdown', 'size', 'Size');
$dd2->setValueList(array('1' => 'small', '2' => 'normal', '3' => 'large'));
$dd2->setModel('Size');
$dd3 = $form->getElement('packaging_id');
if ($_GET['color']) {
$dd3->model->addCondition('color', $_GET['color']);
}
if ($_GET['size']) {
$dd3->model->addCondition('size', $_GET['size']);
}
$dd1->js('change',
$form->js()->atk4_form('reloadField', 'packaging_id',
array($this->api->url(), 'color' => $dd1->js()->val())
)
);
$dd2->js('change',
$form->js()->atk4_form('reloadField', 'packaging_id',
array($this->api->url(), 'size' => $dd2->js()->val())
)
);
With these code the Dropdown dd3 will be filled with the packages, which matching the 'size' OR the 'color' option. But I need, that the Dropdown dd3 will be filled with packages, which matching both, the 'size' AND the 'color' options (for example packages that are 'small' and 'black').
I think, I need a way to achieve the values from both Dropdowns dd1 and dd2 and put it into the 'reloadField' $_GET argument. Then extract it from the $_GET and apply 2 conditions. But I haven't found a way yet. Can anyone help me? Thanks.
ByE...

Description
Parameters for atk4_form are the following:
->atk4_form($js_method, $param1, $param2, $param3, ...)
As result JS method $js_method from ui.atk4_form.js will be called like this:
->$js_method($param1, $param2, $param3, ...)
If method you use is $js_method = 'reloadField', then you can have following parameters:
reloadField: function(field_name, url, fn, notrigger, arg)
So you can pass URL arguments in one (or both) of two ways - using url parameter or using arg parameter.
Solution
So one of these solutions should work for you.
Pass URL parameters already included in URL (using PHP, wrong approach):
->atk4_form(
'reloadField',
'packaging_id',
$this->api->url(null, array( /* base URL + additional parameters, formatted by PHP */
'color' => $dd1->js()->val(),
'size' => $dd2->js()->val(),
))
)
or generate URL dynamically using JS (this is correct way):
->atk4_form(
'reloadField',
'packaging_id',
$this->api->url(), /* base URL */
null,
null,
array( /* additional parameters formatted by JS */
'color' => $dd1->js()->val(),
'size' => $dd2->js()->val(),
)
)

Related

How to change value in the select option of an array in the Yii2 view?

I use Yii2 Framework and I have this array filter for the 'Ordine' column:
[
'attribute' => 'Ordine',
'filterType' => GridView::FILTER_SELECT2,
'filter' => ArrayHelper::map($ordine_nome,'id','ordine'),
'filterWidgetOptions'=>['pluginOptions'=>['allowClear'=>true]],
'filterInputOptions'=>['placeholder'=>'Tutti...'],
'label' => "Ordine",
'width' => '2%',
],
Now, the array is built in this manner:
$ordini=Elenchi::find()->asArray()->orderby(['Ordine' => SORT_ASC])->all();
foreach($ordini as $l){
$ordine_nome[] = ['id'=>$l['Ordine'],'ordine'=>$l['Ordine']];
}
It's all ok. But now I want to change the value in the array select option. For example, if the value is 'OFMCap', in the array selection I want to show 'OFMCap - Ordo fratrum minorum capuccinorum'. At the moment the various selection shows only the acronim (for example OFMCap, etc....)
Anyone can help me to build this type of search?
Thank you very much, I hope to be clear.
You have mapped the same column for id and description
assuming your Elenchi models contains at least two column ordine and description
with values :
ordine description
----- -----------
OFMCap, Ordo fratrum minorum capuccinorum
so the find() return the collection of (at least) these two values
$ordini=Elenchi::find()->asArray()->orderby(['Ordine' => SORT_ASC])->all();
then you should prepare you array as
foreach($ordini as $l){
$ordine_nome[] = ['id'=>$l['ordine'],'description'=>$l['description']];
}
and you map as
'filter' => ArrayHelper::map($ordine_nome,'id','description'),
I have use lower case name for db attribure .. so manage/adapted teh case to your needs
But if you need map directly .you can wrok on array result for map()
$myMap = ArrayHelper::map($ordine_nome,'id','description'),
$myMap['OFMCap'] = 'OFMCap - Ordo fratrum minorum capuccinorum';
'filter' => $myMap,

Calling a static model function from a controller in cakePHP

I am trying to set a default value for select box in CakePHP. My options are accessed using a static function in the model which is defined like so
public static function purpose($value = null)
{
$options = array(
self::PURPOSE_HOMECONSUMPTION => __('Home Consumption', true),
self::PURPOSE_COMMERCIAL => __('Commercial', true)
);
return self::enum($value, $options);
}
// Constants for status attribute
const PURPOSE_HOMECONSUMPTION = '0';
const PURPOSE_COMMERCIAL = '1';
In my view, I fill the select box by calling this static function in this manner
echo $this->Form->input('purpose', array(
'type' => 'select',
'options' => Field::purpose()
Sure enough it picks the options but the default value is Home Consumption. I want to set it Commercial. I tried something like this in the controller
$this->request->data['Field']['purpose'] = Field::purpose(1);
But it doesn't work. Any ideas about how i can call the static function in the controller with the value set to Commercial.
Why are you using class constants and then NOT using them in the code?
Makes no sense to me.
You are on top resolving the integer value into the string. That also does not make sense if you want to use it as default value for a dropdown populated with your enum data.
The correct approach, logically, would be:
// The constant that holds the value 1
$this->request->data['Field']['purpose'] = ModelName::PURPOSE_COMMERCIAL;
Also note that constants should best be real integers, and you should be using tinyint(2) for the db type as mentioned on the blog code.

yii framework main.php use variable of other array in params

I want to do the following:
Create an array inside the main.php params section that uses a value of another array inside that params section.
How can i do that?
Tried something like this:
'params'=>array(
//service types constants
'service_types'=>array(
'st_defect'=>1,
'st_retour'=>2,
'st_order'=>3,
),
//open times of department 0=monday
'st_open'=>array(
**service_types['st_retour']**=>array(
0=>array(800,1700),
1=>array(800,1700),
2=>array(800,1700),
3=>array(800,1700),
4=>array(800,1700),
),
),
), //end params array
The part between ** needs to point to the previous declared array.
How to do that?
You can move services_type to a variable and use it in two places:
$service_types = array(
'st_defect'=>1,
'st_retour'=>2,
'st_order'=>3,
);
return array( /*** .... ****/
'params'=>array(
//service types constants
'service_types'=>$services_types,
//open times of department 0=monday
'st_open'=>array(
$service_types['st_retour']=>array(
0=>array(800,1700),
1=>array(800,1700),
2=>array(800,1700),
3=>array(800,1700),
4=>array(800,1700),
),
),
), //end params array
....
Remember that the config file is just PHP; you can use variables, functions, includes, etc.
Pull the declaration of that array outside the params array declaration:
$service_types = array(
'st_defect'=>1,
'st_retour'=>2,
'st_order'=>3,
);
And then
'params'=>array(
'service_types'=> $service_types
'st_open'=>array(
$service_types['st_retour'] => array(...)
),
)
I changed the configuration of main.php in this:
$ret = array();
$ret['params'] =array();
//service types constants
$ret['params']['service_types']=array(
'st_defect'=>1,
'st_retour'=>2,
'st_order'=>3,
);
//open times of department 0=monday
$ret['params']['st_open']=array(
$ret['params']['service_types']['st_retour']=array(
0=>array(800,1700),
1=>array(800,1700),
2=>array(800,1700),
3=>array(800,1700),
4=>array(800,1700),
);
);
return $ret;
That way i can use the previous declared array inside the next and i keep settings together for a readable format. So settings for one page are clustered.
Thanx for your feedback!

cakephp sort link not working

Can't make sort links work. (concrete or virtual fields).
Vitual fields for my sum() field on this action:
$this->Qca->virtualFields['comps'] = 'Sum(CASE WHEN Qca.qca_tipcode = 1 THEN 1 END)';
$this->Qca->virtualFields['production'] = 'Sum(qca_end - qca_start)';
$this->Qca->virtualFields['idle'] = 'Sum(Qca.qca_durend)';
My find(), works fine:
$hoursvalues = $this->Qca->find('all', array('conditions' => $conditions,
'fields' => array('Qca.dir_id', 'Qca.name', 'Sum(CASE WHEN Qca.qca_tipcode = 1 THEN 1 END) AS Qca__comps', 'Sum(qca_end - qca_start) as Qca__production', 'Sum(Qca.qca_durend) as Qca__idle'),
'group' => array('Qca.dir_id')
)
);
and then:
$this->paginate('Qca' );
$this->set('hoursvalues', $hoursvalues);
What extra settings does $this->paginate('Qca' ); needs? Please note I have all data I need via find().
What is it I'm missing that sorting does not work for either concrete or virtual fields?
Thansk a lot!
Carlos
Part of your problem is the following:
$this->paginate('Qca');
$this->set('hoursvalues', $hoursvalues);
$this->paginate() returns an array with sorted values. What you need to do is specify your extra settings in $this->paginate array and then
$this->set('hoursvalues', $this->paginate('Qca'));
For your other fields, making them virtualFields will make them easier to work with.

Unsetting elements of a cakephp generated array

I have an array called $all_countries following this structure:
Array
(
[0] => Array
(
[countries] => Array
(
[id] => 1
[countryName] => Afghanistan
)
)
[1] => Array
(
[countries] => Array
(
[id] => 2
[countryName] => Andorra
)
)
)
I want to loop through an array called prohibited_countries and unset the entire [countries] element that has a countryName matching.
foreach($prohibited_countries as $country){
//search the $all_countries array for the prohibited country and remove it...
}
Basically I've tried using an array_search() but I can't get my head around it, and I'm pretty sure I could simplify this array beforehand using Set::extract or something?
I'd be really grateful if someone could suggest the best way of doing this, thanks.
Here's an example using array_filter:
$all_countries = ...
$prohibited_countries = array('USA', 'England'); // As an example
$new_countries = array_filter($all_countries, create_function('$record', 'global $prohibited_countries; return !in_array($record["countries"]["countryName"], $prohibited_countries);'));
$new_countries now contains the filtered array
Well first of all id e teh array in the format:
Array(
'Andorra' => 2,
'Afghanistan' => 1
);
Or if you need to have the named keys then i would do:
Array(
'Andorra' => array('countryName'=> 'Andorra', 'id'=>2),
'Afghanistan' => array('countryName'=> 'Afghanistan', 'id'=>1)
);
then i would jsut use an array_diff_keys:
// assuming the restricted and full list are in the same
// array format as outlined above:
$allowedCountries = array_diff_keys($allCountries, $restrictedCountries);
If your restricted countries are just an array of names or ids then you can use array_flip, array_keys, and/or array_fill as necessary to get the values to be the keys for the array_diff_keys operation.
You could also use array_map to do it.
Try something like this (it's probably not the most efficient way, but it should work):
for ($i = count($all_countries) - 1; $i >= 0; $i--) {
if (in_array($all_countries[$i]['countries']['countryName'], $prohibited_countries) {
unset($all_countries[$i]);
}
}
If you wanted to use the Set class included in CakePHP, you could definitely reduce the simplicity of your country array with Set::combine( array(), key, value ). This will reduce the dimensionality (however, you could do this differently as well. It looks like your country array is being created by a Cake model; you could use Model::find( 'list' ) if you don't want the multiple-dimension resultant array... but YMMV).
Anyway, to solve your core problem you should use PHP's built-in array_filter(...) function. Manual page: http://us3.php.net/manual/en/function.array-filter.php
Iterates over each value in the input
array passing them to the callback
function. If the callback function
returns true, the current value from
input is returned into the result
array. Array keys are preserved.
Basically, pass it your country array. Define a callback function that will return true if the argument passed to the callback is not on the list of banned countries.
Note: array_filter will iterate over your array, and is going to be much faster (execution time-wise) than using a for loop, as array_filter is a wrapper to an underlying C function. Most of the time in PHP, you can find a built-in to massage arrays for what you need; and it's usually a good idea to use them, just because of the speed boost.
HTH,
Travis

Resources