I use the code below to get all the categories from the am_category table into a dropdownbox in a form. It works. But when submitting the form I need the category.ID and not the name. How does one usually work with lookup tables like this one?
$category_result = db_query("SELECT id, name FROM {am_category}");
$categories = array();
foreach($category_result as $row)
{
$categories[$row->id] = t($row->name);
}
$form['category_options'] = array(
'#type' => 'value',
'#value' => $categories
);
$form['category']['category'] = array(
'#title' => t('Category'),
'#type' => 'select',
'#description' => t('Please select the category of this achievement.'),
'#options' => $form['category_options']['#value']
);
The value passed through to the $form_state array in your submit function will be the ID and not the name, it will be the key of the options in the drop down, not the value.
If you want to shorten your code slightly you could use the fetchAllKeyed() method of the database query to build that array of categories automatically. You don't need the category_options element as you'll already have access to that array in the $form variable in your submission function.
Also I'd be careful giving the outer and and inner elements the same name (category), that might cause some problems.
This code should help:
function mymodule_myform($form, &$form_state) {
$categories = db_query("SELECT id, name FROM {am_category}")->fetchAllKeyed();
$form['category_wrapper']['category'] = array(
'#type' => 'select',
'#title' => t('Category'),
'#description' => t('Please select the category of this achievement.'),
'#options' => $categories
);
return $form;
}
function mymodule_myform_submit(&$form, &$form_state) {
$selected_category_id = $form_state['values']['category'];
// Just in case you wanted to know, this would get the corresponding name for the selected category:
$selected_category_name = $form['category_wrapper']['category']['#options'][$selected_category_id];
}
Related
I successfully edited the checkout page of the WooCommerce city field in order to be a dropdown field with a lot of cities in it around 13k values the problem is that on mobile and some low-end devices this field isn't performing well how I can make this array load faster is a DB call worth it in this situation, is there any way stop the dropdown and make the field only searchable is it worth splitting the array or loading from a text file?
The code I made
<?php
// Add custom checkout select fields
add_filter('woocommerce_checkout_fields', 'add_custom_checkout_select_fields');
function add_custom_checkout_select_fields($fields)
{
$arr = array(); // very big array arround 13k values
// Define HERE in the array, your desired cities
$cities = $arr;
// Format in the right way the options array of cities
$options = array(
'' => __('Choose City', 'woocommerce') . '…'
);
foreach ($cities as $city)
{
$options[$city] = $city;
}
// Adding 2 custom select fields
$fields['billing']['billing_city2'] = $fields['shipping']['shipping_city2'] = array(
'type' => 'select',
'required' => true,
'options' => $options,
'autocomplete' => 'address-level2',
'input_class' => array(
'wc-enhanced-select',
)
);
// Copying data from WooCommerce city fields
$fields['billing']['billing_city2']['class'] = array_merge($fields['billing']['billing_city']['class'], array(
'hidden'
));
$fields['shipping']['shipping_city2']['class'] = array_merge($fields['shipping']['shipping_city']['class'], array(
'hidden'
));
$fields['billing']['billing_city2']['label'] = $fields['billing']['billing_city']['label'];
$fields['shipping']['shipping_city2']['label'] = $fields['shipping']['shipping_city']['label'];
$fields['billing']['billing_city2']['priority'] = $fields['billing']['billing_city']['priority'] + 5;
$fields['shipping']['shipping_city2']['priority'] = $fields['shipping']['shipping_city']['priority'] + 5;
wc_enqueue_js("
jQuery( ':input.wc-enhanced-select' ).filter( ':not(.enhanced)' ).each( function() {
var select2_args = { minimumResultsForSearch: 1 };
jQuery( this ).select2( select2_args ).addClass( 'enhanced' );
});");
return $fields;
}
Initially i am inserting multiple ids through multiple checkboxes. Now i want to open that page again for edit but i want some of the checkbox checked based on id i have inserted priviously.
$courses contains all the nodes which i need to desplay and $checkedarray are the nodes which comes from database[id which got inserted after submission].
here is the code to uderstand the work..
$vocabulary = taxonomy_vocabulary_machine_name_load('xxx list');
$terms = taxonomy_get_tree($vocabulary->vid);
$courses = array();
foreach($terms as $term) {
if($term->parents[0]==0){
$courses[$term->tid] = $term->name."<br />";
}
else{
$parents = taxonomy_get_parents($term->tid);
$parentsName = $parents[$term->parents[0]]->name.' / ';
$courses[$term->tid] = $parentsName.$term->name."<br />";
}
}
$form['addlicense']['categories'] = array(
'#type' => 'checkboxes',
'#title' => t('Series'),
'#options' => $courses,
'#attributes' => array('class' => array('series-list')),
'#required' => TRUE,
);
$checkedarray = array(5,6,7,8,9,10);
Now i have list of node which need to be appered as checked checkboxes which is in $checkedarray array... any help whould be appreciated
Did you tried using the #default_value attribute and setting it to $checkdarray ?
I have a form having some multi select dropdowns in yii. I have to auto populate the selected values in that multi select box when comes to edit the data. I am fetching the data and passing it inot view file, but am not sure how can i populate the values in the dropdown. please help me
Here is the code for the multi select drop down
echo $form->dropDownListRow($modelDomain, 'domain_id', $domain, array('title' => Yii::t('main', 'SELECT_DOAMIN'),'multiple'=>true ,'style' => 'width:250px;height:150px;'));
For multiple select you need to use 'options' parameter:
echo $form->dropDownListRow($modelDomain, 'domain_id', $domain, array('title' => Yii::t('main', 'SELECT_DOAMIN'),'multiple'=>true ,'style' => 'width:250px;height:150px;', 'options' => array(
1 => array('selected' => 'selected'),
2 => array('selected' => 'selected'),
)));
Where 1 and 2 are domain ids taken from the $_POST;
You can do this in the action:
$post = $this->getRequest()->getPost('ModelName');
$selectedDomains = $post['domain_id']; // this should be an array or selected values
$selected = array_fill(0, count($selectedDomains), array('selected' => 'selected')); // this constructs the 'options' value from view
$selectedOptions = array_combine($selectedDomains, $selected) // this is the 'options' array with selected values as keys and htmlOptions as values
Also, the code is untested and you need to do your validations and other logic stuff yourself.
I have a table called items and a table called item_pics.
item_pics has an item_id, file_name and a rank field (among others).
What I'm looking for is for each item my index page's $items array to contain the file_name from the item_pics matching the item's item_id with the lowest rank. So I can access like (or something like) this in my Items/index.ctp:
foreach ($items as $item):
$img = $item['Item']['ItemPic']['file_name'];
...
I'm pretty new to CakePHP, this is my first project. I thought that this within the Item model would cause item_pics data to be pulled (although I figured all related item_pics for each item would get pulled rather than just the one with the lowest rank):
public $hasMany = array(
'ItemPic' => array(
'className' => 'ItemPic',
'foreignKey' => 'item_id',
'dependent' => false
)
}
but I can see that no item_pics data is loaded (at the bottom of items/index):
SELECT `Item`.`id`, `Item`.`title`, `Item`.`description`, `Item`.`created`, `Item`.`modified`, `Item`.`type`, `Project`.`id`, `Project`.`item_id`, `Project`.`title`, `Project`.`description`, `Project`.`rank`, `Project`.`created`, `Project`.`modified`
FROM `laurensabc`.`items` AS `Item`
LEFT JOIN `laurensabc`.`projects`
AS `Project`
ON (`Project`.`item_id` = `Item`.`id`)
WHERE `Item`.`type` IN (1, 2)
LIMIT 20
also, while I would like projects to be joined in the view pages, I don't really need them in the index page.
I've done some searching and haven't been able to find exactly what I'm looking for. I suppose I could do a query within the index view item loop, but I'm trying to make sure I do things the right way... the CakePHP way. I assume I need to change something about my model relationships but I haven't had any luck.
CakePHP - Associations - HasMany, this makes it seem like I could order by rank and limit 1. But this didn't work... and even if it did, I wouldn't want that to affect the view pages but rather just the index page.
My Controller looks like this:
public function index($type = null) {
$this->Item->recursive = 0;
$conditions = array();
if ($type == "sale") {
$conditions = array(
"Item.type" => array(self::FOR_SALE, self::FOR_SALE_OR_RENT)
);
} else if ($type == "rent" ) {
$conditions = array(
"Item.type" => array(self::FOR_RENT, self::FOR_SALE_OR_RENT)
);
} else {
$conditions = array("Item.type !=" => self::HIDDEN);
}
$paginated = $this->Paginator->paginate($conditions);
debug($paginated);
$this->set('items', $paginated);
$this->set('title', ($type == null ? "Items for Sale or Rent" : "Items for " . ucwords($type)));
}
I have also tried this on my controller, but it doesn't seem to do anything either:
$this->paginate = array(
'conditions' => $conditions,
'joins' => array(
array(
'alias' => 'ItemPic',
'table' => 'item_pics',
'type' => 'left',
'conditions' => array('ItemPic.item_id' => 'Item.id'),
'order' => array('ItemPic.rank' => 'asc'),
'limit' => 1
)
)
);
$paginated = $this->paginate($this->Item);
First, set containable behavior in AppModel (or if you don't want it on each model, put it on Item model):
public $actsAs = array('Containable');
Then, on your find query:
$items = $this->Item->find('all', array(
'contain' => array(
'ItemPic' => array(
'fields' => array('file_name'),
'order' => 'rank',
'limit' => 1
)
)
));
Then the result array you can access it like:
foreach ($items as $item):
$img = $item['ItemPic']['file_name'];
Edit: Then you should put it on the paginate query:
$this->paginate = array(
'conditions' => $conditions,
'contain' => array(
'ItemPic' => array(
'fields' => array('file_name'),
'order' => 'rank',
'limit' => 1
)
)
);
In this case, I would probably order by rank and limit 1 as you said, and make that a dynamic association just for the index page (See http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#creating-and-destroying-associations-on-the-fly). So use $this->Item->bindModel(array('hasMany' => array('ItemPic' => $options))); (which I believe should replace your current settings for HasMany ItemPic, but you may have to unbindmodel first)
Associations created through bindModel will go through for the next query only, then it'll revert to your normal settings, unless you specifically set an option to keep using the new association.
As for why it's not getting ItemPics with Items, or why trying to order by rank and limit 1 didn't work for you, I can't really say without seeing more of your code.
I am trying to create a select list in drupal that is populated from a custom table in my db.
The table consists of a name and an id number. They are both unique.
I used this to collect the data from the db and to populate two arrays.
$query = "SELECT `id`, title` from {svm_mail_esp}";
$result = db_query($query);
$i=0;
while($row = db_fetch_array($result)) {
$listName[$i] = $row['title'];
$listID[$i] = $row['id'];
$i++;
}
Here is the $form array I used:
$form['esp_refferer'] = array(
'#type' => 'select',
'#title' => 'Service Provider',
'#required' => TRUE,
'#options' => $list,
'#cols' => 10,
'#default_value' => '- Choose -', //TODO: This needs to be fixed and the form cannot be processed while this is selected
'#multiple' => FALSE,
);
This is where my problem is coming in, I want to display the name, but when the form is submitted I need the $node->esp_refferer to be the id number and not the name.
How do I do this?
while($row = db_fetch_array($result)) {
$list[$row['id']] = $row['title'];
}
You need to create an array $list, Keys of that array will be ids and value of each will be respective title.