Modify Footers - Description of Selected Data (e.g., Question Name, Skips, Filtering)

From Q
Jump to navigation Jump to search

This rule adds additional descriptive text to the table footer when user-specified questions are shown in the table (e.g., notes about the base). This allows for the addition of descriptions that are relevant only for certain questions. For example, when a question is not shown to all respondents this rule can be used to insert a description of the relevant part of the sample whenever that question is shown in a table. Descriptive text can be added for multiple questions within the same rule.

The best way to use this rule is to apply it to all tables in the project by selecting the Report label at the top of the Report Tree before going to the Online Library.

The rule will ask you to specify:

  1. The questions that you want to apply additional footer information for.
  2. The extra descriptive text that should be added for each of the specified questions.

Note that you can add many sets of descriptive text at once using the QScript Modify Footers - Add Descriptions of Selected Data (e.g., Question Name, Skips, Filtering) from File.


If we would like every table that shows the question Q10. Why drinks more than one cola to include an extra description in the footer that tells us which respondents skipped the question, then the input to this rule would be:


Note that once the descriptive text has been specified for one question there is additional room to add text for other questions. The resulting table is shown with its footer:


The footer below the table shows some additional text: Q10: Skipped by respondents who drank less than 2 per week. This rule allows this text to be shown in the footer for any table or chart that has Q10. Why drinks more than one cola selected.

Technical details

  • When selecting the question you can either type in the name of a question, or choose a question from the list.
  • When you type in text from the question the message will be applied for any question whose name contains the text. Typing in the name of the question will help the rule to persist if the name of the question is changed elsewhere in the project.
  • Making a selection from the list will override any text that has been typed in.

How to apply this rule

For the first time in a project

  • Select the table(s)/chart(s) that you wish to apply the rule to.
  • Start typing the name of the Rule into the Search features and data box in the top right of the Q window.
  • Click on the Rule when it appears in the QScripts and Rules section of the search results.


  • Select Automate > Browse Online Library.
  • Choose this rule from the list.

Additional applications of the rule

  • Select a table or chart that has the rule and any table(s)/chart(s) that you wish to apply the rule to.
  • Click on the Rules tab (bottom-left of the table/chart).
  • Select the rule that you wish to apply.
  • Click on the Apply drop-down and choose your desired option.
  • Check New items to have it automatically applied to new items that you create. Use Edit > Project Options > Save as Template to create a new project template that automatically uses this rule.

Removing the rule

  • Select the table(s)/chart(s) that you wish to remove the rule from.
  • Press the Rules tab (bottom-right corner).
  • Press Apply next to the rule you wish to remove and choose the appropriate option.

How to modify the rule

  • Click on the Rules tab (bottom-left of the table/chart).
  • Select the rule that you wish to modify.
  • Click Edit Rule and make the desired changes. Alternatively, you can use the JavaScript below to make your own rule (see Customizing Rules).


includeWeb('QScript Utility Functions')
includeWeb('Table JavaScript Utility Functions'); 


// Set descriptive elements for the form
form.setHeading(correctTerminology('Description of Selected Data (e.g., Question Name, Skips, Filtering)'));
const description_text = 'This rule adds additional descriptive text to the table footer when user-specified ' +
                         'questions are shown in the table (e.g., notes about the base).'
const description = form.newLabel(correctTerminology(description_text));
description.lineBreakAfter = true;

// Modifying Footers - Description of Selected Data (e.g., Question name, skips, filtering)

let question_name_list;
let question_name_list_with_files;

// Get a list of names of questions in all data files.
// If there are multiple data files then each name must have the datafile name appended.
if (project.dataFiles.length > 1) {
    let all_questions = [];
	project.dataFiles.forEach(function (data_file) {
		all_questions = all_questions.concat(data_file.questions.filter(function (q) { return !q.isHidden; }));
	question_name_list = [''].concat( (q) { return; }));
	question_name_list_with_files = [''].concat( (q) { return + ' [' + + ']' ; }));
} else {
	question_name_list = [''].concat(project.dataFiles[0].questions.filter(function(q) { return !q.isHidden; })
											.map(function (q) { return; }));
	question_name_list_with_files = question_name_list.slice(0);

// Form for question selection and message entry
// Repeat while selections continue to be made
let form_counter = 0;
let last_selection = ' ';
let last_message = ' ';
let control_array = [description];
let target_questions = [];
let display_names = [];
let messages = [];
while (last_selection != '' && last_message != '') {

	// Drop-down menu with list of question names
	let question_selection_label = form.newLabel(correctTerminology('Choose a question:'));
	let question_selection_menu = form.newComboBox('qselection' + form_counter, question_name_list_with_files);

	// Text box to enter partial question name
	let question_text_box_label = form.newLabel(correctTerminology('         OR      Enter all or part of the question name:'));
	let question_text_box = form.newTextBox('qnametext' + form_counter);
    question_text_box.lineBreakAfter = true;

	// Text box to type footer text
	let footer_type_label = form.newLabel('Footer text: ');
	let footer_box = form.newTextBox('ft' + form_counter);
	footer_box.lineBreakAfter = true;

	// Add controls to existing array of controls
	let new_control_array = [question_selection_label, question_selection_menu, question_text_box_label,
                             question_text_box, footer_type_label, footer_box];
	control_array = control_array.concat(new_control_array);

	// Get user-entered values
	let typed_name = question_text_box.getValue();
	let selected_name = question_selection_menu.getValue();
	let selected_name_without_file = question_name_list[question_name_list_with_files.indexOf(selected_name)];
	let message = footer_box.getValue();
	// Determine which question to use
	let matched_questions = [];
	let display_name = '';

	if (selected_name_without_file != '') {
		// Menu selection overrides typed name
		matched_questions = [selected_name_without_file];
		display_name = selected_name_without_file;
	} else if (typed_name != '') {
		// Multiple matches are allowed
		matched_questions = question_name_list.filter(function (name) { return name.indexOf(typed_name) > -1; });
		if (matched_questions.length == 0)
			form.ruleNotApplicable(correctTerminology('the entered name \'' + typed_name + '\' does not match any questions'));
		display_name = typed_name;
	} else if (selected_name == '' && message != '')
		form.ruleNotApplicable(correctTerminology('no question selected for footer text: ' + message));
	// Add selections to existing array of selections
	target_questions = target_questions.concat(matched_questions);
	// Add the message once for each of the identified target questions
	matched_questions.forEach(function (x) {


	// Repeat loop
	last_message = message;
	last_selection = display_name;

// Set summary with selected question named

if (display_names.length === 0)
    form.ruleNotApplicable(correctTerminology('footer text needs to be specified'));
let question_text_for_label = display_names.slice(0,2).join(', ');
if (display_names.length > 2)
	question_text_for_label += '...';
form.setSummary('Add description to footer when table shows: ' + question_text_for_label);

// If any of the selected questions are present in the table add footers
let footers = table.extraFooters;
let blue_index = target_questions.indexOf(;
let brown_index = target_questions.indexOf(table.brown);
if (blue_index > -1){
	let new_blue_footer = messages[blue_index];
	if (footers.indexOf(new_blue_footer) == -1)
if (brown_index > -1) {
	let new_brown_footer = messages[brown_index];
	if (footers.indexOf(new_brown_footer) == -1)

table.extraFooters = footers;

See also