Custom Field with autcomplete - drupal-7

I am trying to build my own node reference custom field - I know several projects out there already do this, I am building this in order to learn... :)
My problem is the autocomplete path, it's not being triggered, I have checked the noderefcreate project and implemented my solution based on that project. But still; nothing is being triggered when I check firebug.
Here is my code:
function nodereference_field_widget_info() {
return array(
'nodereference_nodereference_form' => array(
'label' => t('Node Reference Form'),
'field types' => array('nodereference'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
'settings' => array(
'autocomplete_match' => 'contains',
'autocomplete_path' => 'nodereference/autocomplete',
),
),
);
}
function nodereference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
if ($instance['widget']['type'] == 'nodereference_nodereference_form') {
$widget = $instance['widget'];
$settings = $widget['settings'];
$element += array(
'#type' => 'textfield',
'#default_value' => isset($items[$delta]['nid']) ? $items[$delta]['nid'] : NULL,
'#autocomplete_path' => $instance['widget']['settings']['autocomplete_path'],
);
}
return array('nid' => $element);
}

You need to define method from where auto compete will take suggestions.
It can be done like this:
/**
* implements hook_menu
*/
function your_module_name_menu() {
$items['master_place/autocomplete'] = array(
'page callback' => '_your_module_name_autocomplete',
'access arguments' => array('access example autocomplete'),
'type' => MENU_CALLBACK
);
return $items;
}
/**
* Auto complete method implementation
* #param $string
*/
function _your_module_name_autocomplete($string) {
$matches = array();
// Some fantasy DB table which holds cities
$query = db_select('target_db_table', 'c');
// Select rows that match the string
$return = $query
->fields('c', array('target_column'))
->condition('c.target_column', '%' . db_like($string) . '%', 'LIKE')
->range(0, 10)
->execute();
// add matches to $matches
foreach ($return as $row) {
$matches[$row->city] = check_plain($row->city);
}
// return for JS
drupal_json_output($matches);
}

Related

Updating and deleting data in D7

I have made a form in D7 using form API, registered some users and retrieved their registered data from database;now what i want is to add an edit and a delete link in front of every row in the retrieved table;i have done that in PHP but how to implement same in Drupal?;anybody having any idea how to do that?
My retrieval code is:
function form_data_menu() {
$items['formdata'] = array(
'title' => 'Form Data',
'page callback' => 'form_data_form',
'access callback' => TRUE,
);
return $items;
}
function form_data_form()
{
$results = db_query('SELECT * FROM {drupal}');
$header = array(t('Id'),t('Name'),t('College'),t('Education'),t('Percentage'),t('Application'));
$rows = array();
foreach($results as $result) {
$rows[] = array(
$result->id,
$result->name,
$result->college,
$result->education,
$result->percentage,
$result->application,
);
}
return theme('table',array('header'=>$header,'rows'=>$rows));
}
I can add links though but the main problem is how to run update and delete queries in D7?
Any help will be appreciated. Thank you!
Start with the example module "dbtng_example.module".
https://www.drupal.org/project/examples
This will give an example of how to set up a module to save to the database. I used this recently to create a custom module to save data to a new database table within drupal. To figure out how to set up the hook_schema, you can look at ".install" files within the drupal core and contributed codebase.
Then to create an edit or delete link, you need to alter your hook_menu to pass in the unique id for that element:
$items['admin/structure/nates-custom-page/update/%'] = array(
'title' => 'Update entry',
'page callback' => 'drupal_get_form',
'page arguments' => array('nates_module_form_update', 5),
'weight' => -5,
'access arguments' => array('administer DFP'),
);
$items['admin/structure/nates-custom-page/delete/%'] = array(
'title' => 'Delete entry',
'page callback' => 'drupal_get_form',
'page arguments' => array('nates_module_form_delete', 5),
'access arguments' => array('administer DFP'),
);
Above is an example where I added the argument (indicated by the percentage sign in the array key, ("%"), that will represent the unique id for that item I want to edit or delete.
Then alter the edit form to load the item you want to edit by the id.
And add a delete form.
Here's an example of a delete form:
function nates_module_form_delete($form, &$form_state) {
$entry = nates_module_entry_load_by_pid(arg(5));
$form = array();
$form['pid'] = array(
'#type' => 'value',
'#value' => arg(5),
);
$output = "";
foreach($entry as $key => $value) {
$output .= "<p><strong>$key</strong>: $value</p>";
}
$form['markup'] = array(
'#type' => 'markup',
'#markup' => $output,
);
return confirm_form(
$form,
t('Are you sure you want to delete this item? '),
'example/list',
t('This action cannot be undone.'),
t('Delete'),
t('Cancel')
);
return $form;
}
Notice I return a confirmation form first.
And here's the submit handler function that processes it after they submit the request:
function nates_module_form_delete_submit($form, &$form_state) {
global $user;
nates_module_entry_delete($form_state['values']['pid']);
drupal_set_message(t("Deleted entry"));
}
Then, edit your listing page to add the edit links and delete links:
function nates_module_list() {
$output = '';
// Get all entries in the dfp_amobee2 table.
if ($entries = nates_module_entry_load_all()) {
$rows = array();
foreach ($entries as $entry) {
// Sanitize the data before handing it off to the theme layer.
$entry->editlink = l('edit','admin/structure/nates-custom-page/update/' . $entry->pid, array('query' => array('destination' => 'admin/structure/nates-custom-page')));
$entry->deletelink = l('delete','admin/structure/nates-custom-page/delete/' . $entry->pid, array('query' => array('destination' => 'admin/structure/nates-custom-page')));
unset($entry->pid);
if(!empty($entry->tid)) {
$entry->alias = l($entry->alias, 'taxonomy/term/'.$entry->tid);
}
else if(isset($entry->pages)) {
if(drupal_valid_path($entry->pages)) {
$entry->alias = l(drupal_lookup_path('alias', $entry->pages),$entry->pages);
} else {
$entry->alias = check_markup($entry->pages);
}
} else {
$entry->alias = "";
}
unset($entry->pages);
if(!$entry->tid) {
$entry->tid = "";
}
$rows[] = (array) $entry;
}
// Make a table for them.
$header = array(t('path'), t('tid'), t('dfp tag machine_name'),t('amobee_as'), '', '');
$output .= '<p>' . t('If the "tid" is filled in, amobee_as will be used on taxonomy pages and on node pages (where the main term id matches). If the path is filled it, will be used on that path. Path supercedes "tid" when there is a conflict.') . '</p>';
$output .= theme('table', array('header' => $header, 'rows' => $rows));
}
else {
drupal_set_message(t('No entries have been added yet.'));
}
return $output;
}

CakePHP: Keep the same checkboxes checked after submit

How can I keep the same checkboxes checked after submit? All the other input fields on the form automatically keeps the values. I thought this would also go for checkboxes, but nope.
echo $this->Form->input('type_id', array(
'multiple' => 'checkbox',
'options' => array(
'1' => 'Til salgs',
'2' => 'Ønskes kjøpt',
'3' => 'Gis bort'
),
'div' => false,
'label' => false
));
I believe this can be done in the controller, but how?
Edit:
Since I posted this question I've changed to CakeDcs Search plugin, because I've gotten this to work with that before. Still... I can't get it to work this time.
Adding model and controller code:
AppController
public $components = array('DebugKit.Toolbar',
'Session',
'Auth' => array(
'loginAction' => '/',
'loginRedirect' => '/login',
'logoutRedirect' => '/',
'authError' => 'Du må logge inn for å vise denne siden.',
'authorize' => array('Controller'),
),
'Search.Prg'
);
public $presetVars = true; //Same as in model filterArgs(). For Search-plugin.
AdsController
public function view() {
$this->set('title_for_layout', 'Localtrade Norway');
$this->set('show_searchbar', true); //Shows searchbar div in view
$this->log($this->request->data, 'debug');
//Setting users home commune as default filter when the form is not submitted.
$default_filter = array(
'Ad.commune_id' => $this->Auth->user('User.commune_id')
);
$this->Prg->commonProcess(); //Search-plugin
$this->paginate = array(
'conditions' => array_merge($default_filter, $this->Ad->parseCriteria($this->passedArgs)), //If Ad.commune_id is empty in second array, then the first will be used.
'fields' => $this->Ad->setFields(),
'limit' => 3
);
$this->set('res', $this->paginate());
}
Model
public $actsAs = array('Search.Searchable');
public $filterArgs = array(
'search_field' => array('type' => 'query', 'method' => 'filterSearchField'),
'commune_id' => array('type' => 'value'),
'type_id' => array('type' => 'int')
);
public function filterSearchField($data) {
if (empty($data['search_field'])) {
return array();
}
$str_filter = '%' . $data['search_field'] . '%';
return array(
'OR' => array(
$this->alias . '.title LIKE' => $str_filter,
$this->alias . '.description LIKE' => $str_filter,
)
);
}
/**
* Sets the fields which will be returned by the search.
*
* #access public
* #return array Database table fields
* #author Morten Flydahl
*
*/
public function setFields() {
return array(
'Ad.id',
'Ad.title',
'Ad.description',
'Ad.price',
'Ad.modified',
'User.id',
'User.first_name',
'User.middle_name',
'User.last_name',
'User.link',
'User.picture_url',
'Commune.name',
'Type.id',
'Type.name'
);
}
You have to set manually the selected option of the input, as an array with "keys = values = intval(checkbox id)"
I cannot explain why this format, but this is the only way I get it to work.
Here is my code:
echo $this->Form->create('User');
// Read the submitted value
$selected = $this->Form->value('User.Albums');
// Formats the value
if (empty($selected)) {
$selected = array(); // avoid mess
} else {
$selected = array_map('intval', $selected);
$selected = array_combine ($selected, $selected);
}
// Renders the checkboxes
echo $this->Form->input('Albums',array(
'type' => 'select',
'multiple' => 'checkbox',
'options' => $albums, // array ( (int)id => string(label), ... )
'selected' => $selected, // array ( (int)id => (int)id, ... )
));
Hope this helps.
++

Populating #options, #header for tableselect in ajax callback function

What I am trying to do is display a table with checkboxes on the press of a button by ajax. The table should be initially hidden and get populated on the fly by a function call.
If initially I load $options1 with some dummy values , then after ajax call it throws in an error saying-
Notice: Undefined index: red in theme_tableselect() (line 3285 of
D:\wamp\www\drupal7\includes\form.inc).
where 'red' is the index of a dummy row value and #options don't get populated with the new values. What is the way to get this working ?
Here is the code for the form-
$form['mltag_new']['tag'] = array(
'#type' => 'button',
'#value' => t("Suggest Tags"),
'#ajax' => array(
'callback' => 'mltag_suggest_tags_ajax',
'wrapper' => 'mltag_suggest_tags_table_div',
'effect' => 'slide',
),
);
$options1 = array(); //initial dummy values
$options1['red']['tag'] = "A red row";
$options1['red']['chi'] = "A red row";
$form['mltag_new']['myselector'] = array (
'#type' => 'tableselect',
'#title' => 'My Selector',
'#header' => $header,
'#options' => $options1,
'#prefix' => '<div id="mltag_suggest_tags_table_div">',
'#suffix' => '</div>',
);
return $form;
and the Ajax callback looks something like this-
function mltag_suggest_tags_ajax($form, $form_state) {
//$content has some content
//pass the content to a function
include_once 'includes/content_tag.inc';
$tags = mltag_content_tag($content, variable_get('algo_type'), 20);
if (empty($tags)) {
$output .= t('Content is insufficient to generate Tags using this algorithm. <br>Please choose other algorithm from Settings Page.');
$form['mltag_new']['sample_text']['#markup'] = $output;
return $form['mltag_new']['sample_text'];
}
else {
$algo = variable_get('algo_type');
if ($algo == 1) {
$header = array(
'tag' => t('Tag'),
'frequency' => t('Frequency'),
);
$options = array();
foreach ($tags as $key => $value) {
$options[$key] = array(
'tag' => $key,
'frequency' => $value,
);
}
}
elseif ($algo == 2) {
$header = array(
'tag' => t('Tag'),
'chi' => t('Chi Square Value'),
);
$options = array();
foreach ($tags as $key => $value) {
$options[$key] = array(
'tag' => $key,
'chi' => $value,
);
}
}
$form['mltag_new']['myselector']['#header'] = $header;
$form['mltag_new']['myselector']['#options'] = $options;
return $form['mltag_new']['myselector'];
}
}
I replied to your post on Drupal.org about how I'm working on a somewhat similar problem. Try adding
$form['mltag_new']['myselector'] =
form_process_tableselect($form['mltag_new']['myselector']);
just before your return. Hopefully that helps you more than it did me. Beware that the #options just get rendered when the block reloads from the ajax, but the original $form object doesn't seem to be aware.
I know that this is a few years later, but I found this while searching for my own solution:
The tableselect module creates checkboxes in the $ form that have to be removed. in the example above, they would be in $form['mltag_new']['myselector'] with keys equal to the original $option1 in your original code. If you unset those, then call
$form['mltag_new']['myselector'] = form_process_tableselect($form['mltag_new']['myselector']);
before your return, it will eliminate the dummy rows.

cakephp beforeSave callback in Behaviors don't save data correctly

Controller:
$data =
array(
'ContentI18n' =>
array(
0 =>
array(
'title' => 'first',
'author' => 'first',
'source' => 'sgfsdfrst',
'lang' => 'fa',
),
),
'Content' =>
array(
'publish' => 1,
'type' => 3,
'pages' => 8,
'volume' => 7,
'modified' => '2012-05-27 14:16:37',
'created' => '2012-05-27 14:16:37',
'lang' => 'fa',
),
);
$this->Content->create();
$this->Content->saveAll($data);
Model:
public $hasMany = array(
'ContentI18n' => array(
'className' => 'ContentI18n',
)
);
beforeSave function in behavior:
public function beforeSave(Model $model) {
// Define the new Translate model
App::uses($model->name . 'I18n', 'Model');
$varI18n = $model->name . 'I18n';
$modelI18n = new $varI18n;
foreach ($model->data[$model->name] as $key => $data) {
if (!in_array($key, $this->setting))
$modelData[$model->name][$key] = $data;
else
$modelData[$model->name . 'I18n'][0][$key] = $data;
}
$modelData[$model->name . 'I18n'][0]['lang'] = $model->locale;
$modelData[$model->name]['lang'] = $model->locale;
$model->data = $modelData;
//pr($model->data);
return TRUE;
}
every things seems be cause when is save it directly it's save with saveAll. but when i use same structure of data in behavior did not work without any error.
I found out that beforeSave callback will not trigger by saveAll. for executing some code before saveAll we must override saveAll function in our model.
public function saveAll($data, $options = array()) {
/*
your code you want execute before saving...
*/
parent::saveAll($data, $options);
}
for other saving methods such as saveMany,saveAssociated,... beforeSave trigger by them.

Print terms from a specific vocab at page.tpl drupal 7

I used to have a function to create a custom menu by loading all terms from a specific vocab at drupal 6:
function _taxonomy_top_links($vid = NULL) {
$terms = taxonomy_get_tree($vid);
$taxos = array();
foreach ($terms as $term) {
$taxos[] = array('title' => $term->name, 'taxonomy/term/' . $term->tid, 'attributes' => array('rel' => 'tag', 'title' => strip_tags($term->description)));
}
return theme('links', $taxos, array('id' => 'menu-'. $vid, 'class' => 'menu clearfix'));
}
This doesn't work at drupal 7 which I guess related to the new field api. How do you grab all terms from a specific vocab to preprocess at page level?
Thanks for any help.
Most of your code should actually work fine, it's the theme part that is incorrect.
$terms = taxonomy_get_tree($vid, 0, NULL, TRUE);
$links = array();
foreach ($terms as $term) {
$uri = entity_uri('taxonomy_term', $term);
$link = array(
'title' => $term->name,
'href' => $uri['path'],
'attributes' => array('rel' => 'tag'),
);
$link += $uri['options'];
if (!empty($term->description)) {
$link['title'] = strip_tags($term->description);
}
$links['tid-' . $term->tid] = $link;
}
$variables = array(
'links' => $links,
'attributes' => array(
'id' => 'menu-' . $vid,
'class' => array('menu', 'clearfix'),
),
);
return theme('links', $variables);

Resources