Hi everyone,
Here is a wild idea.
I want to make a "report generator" for users. The idea is to create a master table view (lots of rows, lots of fields/columns). Users would have a link that says "generate custom report". They would be taken to a form that is essentially an exposed filter form, plus a list of the data fields with checkboxes (or similar). They would be able to select all fields, or just a subset.
The views exposed filter part already exists obviously, and I've gathered is that the columns part would involve dynamically overriding the "exclude from view" property for the fields. Ideally the field visibility option would be passed through the URL in a similar way to filters, which would allow users to bookmark favorite setups and would allow admins to offer presets through links. If the view data structure is correctly modified, then it would also allow to export to excel/create custom feeds and so on.
Here's the two part question:
1. Are there any modules that allow toggling the "exclude from view" variable from the user standpoint? (dynamically, through arguments, and so on)
2. If there aren't modules that could help, does anyone have pointers as to where to start to develop a module to do this? I am willing to give it a shot as I think it would be a useful feature for many corporate/intranet/project management sites.
Many thanks,
Delphine
ps. I've also considered using one of the many jQuery table utilities to hide columns from view, but this would not achieve the robustness I am looking for, so I'd rather keep that as a last resort.
Comments
Starting thoughts
I love your idea and I had the same requirement including the export to excel feature.
I'm not an expert on views but I thought creating a views display plugin might be the way to go? The plugin should automatically list the fields chosen for the view using checkboxes to start with. The user can select the fields they want to see and enter any other fields (I suppose a date range field would be used in tandem to this) and submit the form. Thereby the view will be displayed with only the selected fields. The previous form submit should do the 'exclude from view'.
As for export to excel, this module looks promising http://drupal.org/project/views_export_xls although I feel it could be extended to other file types as well. I am yet to play around with this. I shall post my feedback.
Cheers,
Girish
Any progress?
Hi Girish,
Any progress on this one Girish?
Views explort xls works fine
Hey Capoyeti,
I have not been able to get the 'dynamically pick and choose' of the fields working for my view. Primarily because using a static set of fields was actually enough for me in the end - like the general behaviour of views.
I however got my 'export to excel' feature working well using Views_export_xls module. I had to create a default view, a page view (for the actual view) and a feed view (for the xls). The xls reads the properties of the default view (such as items_per_page). But I needed pagination on my page view so I edited the page view and overrode the settings there. The xls had to display 'all results', hence set my default view to display unlimited number of items. This is working for me.
Its unfortunate that I have not been able to put some effort into building the 'dynamic select' of fields.
This works for me for now
Thanks Girish - the static approach is good enough for now, but I'm looking forward to how you progress below on the dynamic views...
Exclude fields programatically
You can exclude fields using hook_ views_pre_build
See my second code snippet here:
http://groups.drupal.org/node/82219
I am working on a project for this
Hi guys,
Just to let you know, I am working to create a project on this. I have not released this or checked into Drupal yet since its still in the works.
But the basic functionality of choosing which fields to include in the view works. For this I have created a filter handler called views_handler_filter_dynamic_fields. See code below.
<?php
/**
* Simple filter to choose which fields to include in the view
*/
class views_handler_filter_dynamic_fields extends views_handler_filter {
var $no_single = TRUE;
function option_definition() {
$options = parent::option_definition();
return $options;
}
/**
* Provide default options for exposed filters.
*/
function expose_options() {
parent::expose_options();
}
function operators() {
// no operators
return array();
}
/**
* Provide a list of all the numeric operators
*/
function operator_options($which = 'title') {
$options = array();
foreach ($this->operators() as $id => $info) {
$options[$id] = $info[$which];
}
return $options;
}
function operator_values($values = 1) {
$options = array();
foreach ($this->operators() as $id => $info) {
if ($info['values'] == $values) {
$options[] = $id;
}
}
return $options;
}
/**
* Provide a list of all fields that are for display
*/
function value_form(&$form, &$form_state) {
$form['value']['#tree'] = TRUE;
$all_fields = array();
foreach ($this->view->field as $field_name => $field) {
// TODO: Fields already marked as 'exclude from display' in the original view should be omitted from this list
$all_fields[$field_name] = $field->label();
$field_names[] = $field_name;
}
// TODO: Test this feature where views_handler_filter says checkboxes don't work so well in exposed forms due to GET conversions
$this->options['expose']['single'] = ''; // otherwise views_handler_filter will change this to use 'select'
// Ensure there is something in the 'value'.
// $form['value'] = array(
// '#type' => 'value',
// '#value' => NULL
// );
$form['value'] = array(
'#type' => 'checkboxes',
'#no_convert' => TRUE,
'#title' => t('Fields to be displayed'),
'#default_value' => $field_names,
'#options' => $all_fields,
'#description' => t('Choose the fields to be displayed in the view'),
);
// $form['value'] = array(
// '#type' => 'checkbox',
// '#default_value' => $this->options['expose']['reverse'],
// '#title' => t('Show fields to be excluded'),
// '#description' => t('Choose the fields to be excluded from the view'),
// );
}
function pre_query() {
$exposed_input = $this->view->get_exposed_input();
// Get all fields
foreach ($this->view->field as $field_name => $field) {
$all_fields[$field_name] = $field->label();
$field_names[] = $field_name;
}
if (!empty($exposed_input[$this->options['expose']['identifier']])) {
$fields_to_exclude = array_diff($field_names, $exposed_input[$this->options['expose']['identifier']]);
foreach ($fields_to_exclude as $field_to_exclude) {
$this->view->field[$field_to_exclude]->options['exclude'] = 1;
}
}
}
function query() {
}
function admin_summary() {
if (!empty($this->options['exposed'])) {
return t('exposed');
}
$options = $this->operator_options('short');
$output = check_plain($options[$this->operator]);
if (in_array($this->operator, $this->operator_values(2))) {
$output .= ' ' . t('@min and @max', array('@min' => $this->value['min'], '@max' => $this->value['max']));
}
elseif (in_array($this->operator, $this->operator_values(1))) {
$output .= ' ' . check_plain($this->value['value']);
}
return $output;
}
/**
* Do some minor translation of the exposed input
*/
function accept_exposed_input($input) {
if (empty($this->options['exposed'])) {
return TRUE;
}
// rewrite the input value so that it's in the correct format so that
// the parent gets the right data.
if (!empty($this->options['expose']['identifier'])) {
$value = &$input[$this->options['expose']['identifier']];
if (!is_array($value)) {
$value = array(
'value' => $value,
);
}
}
$rc = parent::accept_exposed_input($input);
if (!empty($this->options['expose']['optional'])) {
// We have to do some of our own optional checking.
$info = $this->operators();
if (!empty($info[$this->operator]['values'])) {
switch ($info[$this->operator]['values']) {
case 1:
if ($value['value'] === '') {
return FALSE;
}
break;
case 2:
if ($value['min'] === '' && $value['max'] === '') {
return FALSE;
}
break;
}
}
}
return $rc;
}
}
Basically you just need to include this filter in your code, then in your module's hook_views_handlers(), register this filter like so:
function exampleModule_views_handlers() {'views_handler_filter_dynamic_fields' => array(
'parent' => 'views_handler_filter',
),
}
And also then define a dummy field to attach this filter to (this is a round-about approach, since I don't know better).
function exampleModule_views_data_alter(&$data) {$data['node']['myfield'] = array(
'real field' => 'nid',
'title' => t('Choose fields),
'help' => t("Filter that displays a list of all fields as checkboxes which can be used to decide which fields to include in the view"),
'filter' => array(
'handler' => 'views_handler_filter_dynamic_fields',
),
);
}
This is working well for me (although using a bit of a round-about approach). Any feedback would be appreciated on how to improve this as my knowledge of views is mindbogglingly low :)
Cheers,
Girish
This is just a short code
This is just a short code suggestion: you don't have to write something which is already in the parent class
function option_definition() {
$options = parent::option_definition();
return $options;
}
/**
* Provide default options for exposed filters.
*/
function expose_options() {
parent::expose_options();
}
as a example.
Still in works..
Thanks Dereine..I added those as I was initially working on those functions. Still left them there presuming I'd need them. I just cut and pasted from my working copy. I have lots to clean up. Was anybody able to try the filter above? Meets expectations? Cheers.
You might have also noticed I'm reusing views_handler_filter_numeric as the admin_summary() and functions below it haven't been removed as well.
CVS application review
@dereine: Could you help review the code of this proposed module over in http://drupal.org/node/867300 ?
Daniel F. Kudwien
netzstrategen
Here's the link to the module
Here's the link to the module Views dynamic fields. I'd be really interested to see if it answers the goals and if not, what bugs/feature requests you have.