Jump to content

new templete field


muzzer
 Share

Recommended Posts

I've come to a situation which I have not come across previously and am wondering how best to solve.

I have a template with a heap of "questions" which usually have a yes/no answer, but may also need further detail. So a textfield with a simple yes, no, or other text such are "sometimes" would cover it.

But I'd also like a couple of additional checkboxes to accompany each of these fields as a toggle for display; eg

For example:

do you have children? yes, Display this field (yes), Include field in emails (no)

do you have pets? (yes, 2 rabbits) Display this field (no), Include field in emails (yes)

do you have rabies? (sometimes), Display this field (yes), Include field in emails (yes)

 
...etc, you get the picture. I have probably 50-80 fields like the above.
 
How would I go about doing this? Is this what is referred to in Processwire as a custom fieldtype? Are there any really basic tutorials or examples for something like this?

 
Link to comment
Share on other sites

Hehe...who has rabies sometimes? :)

Anyway, I'm not sure if you want the user to select all these additional settings for each field, or whether you want to choose it for them based on their answer to the first bit of each question? (Or is each question its own field ?? )

If it's the former (user should answer and select settings as well), maybe look at the table field? https://processwire.com/api/modules/profields/table/ So each row of the field would have 4 columns: a question, its answer, its display setting and email-inclusion setting. You would set the first field (question) and the user can provide the answer in the second, and they can also check/uncheck the third and fourth. I have tried using it once, and I think (I think) the way in which it is different from repeater is that you must specify a range of how many total rows you will need. I wanted to use it for comments so it didn't really work, but it might be just right for your case if you want a lot of input of different types but same pattern grouped together, and you know exactly how many. If you are currently creating new fields for every question, table field might help you eliminate it. Just use an additional column called "name" or something for each row, which will help you identify what your question was (for using it in the API). "children", "pets", "rabies" - just like fieldnames...

If you want to show them specific fields based on their answer to "Do you have pets" etc... I'm not sure. Maybe inputfield dependencies? http://processwire.com/api/selectors/inputfield-dependencies/

Sorry, hope it helps..

  • Like 1
Link to comment
Share on other sites

Assuming that the structure of the fields is always the same (Question, Checkbox 1, Checkbox 2), I think that the approach depends on who defines the questions:

  1. the user (like a "create your own form" type of page)
  2. You (with a fixed set of questions that the user must answer on the page)

In the first case, you could use the Profield Table, as suggested by nickie, or even simpler, a PageTable (which is not a Profield):

  • You create a template called question, with the fields question_text (text field), question_answer (text field), display (checkbox field), include_in_email (checkbox field).
  • Then you create a PageTable field questions, that uses this question template.
  • Finally you add this questions field to the target template.

This way, the user can add as many questions as he wishes on a page.

The second case is more difficult. The "pure" way of doing it would be to create a field for each question's subquestion, i.e children_answer, children_display, children_email, pets_answer, pets_display, pets_email, etc. The problem is that this would create an enormous amount of fields, which becomes inefficient (see this post from Ryan). You could create your own compound Fieldtype to group the three subquestions in one field (see the Events Fieldtype/Inputfield as an example), but this would still require 50-80 different fields, which is a lot.

I think that the approach that I would attempt is the following:

  • Create a question template with fields question_text (text field, with visibility set to visible but not editable), answer_text (text field), display (checkbox field) and include_in_email (checkbox field).
  • Create a questions PageTable field that uses this question template.
  • Add the questions field to the target template (let's call it questionnaire).
  • Write a module to hook after Pages::added, so that each time a questionnaire page is created, it adds the question pages under it. Here is an example of what I mean:
// Inside a module

public function init() {
  $this->addHookAfter("Pages::added", function($event) {
    // Activate the hook only if the added page is a questionnaire
    if ((string)$event->arguments(0)->template == "questionnaire"
      $this->hookAdded($event);
  });
}

public function hookAdded($event) {
  $questionnaire = $event->arguments(0);

  // List of all your questions
  $questions = array(
    "Do you have children?",
    "Do you have pets?",
    "Do you have rabies?",
    // etc.
  );

  foreach($questions as $q) {
    // Create a question page under the new questionnaire
    $p = new Page();
    $p->template = "question";
    $p->parent = $questionnaire;
    $p->question_text = $q;
    $p->save();

    // Add the question page to the questions field of the questionnaire
    $questionnaire->questions->append($p);
  }
  // Save the questions field of the questionnaire
  $questionnaire->save("questions");
}

You should also adjust the permissions for the question template so that a user can't delete them.

Yet other approaches would be to create a custom Process module (see the Hello Process Module for an example), or to set up a custom front-end template to answer the questions instead of using the admin back-end.

  • Like 4
Link to comment
Share on other sites

Thx for the detailed replies.

Just to clarify as there appears to be some confusion on what I'm trying to achieve;

The questions will be set on the template - ie, they do not change. The user answers them all. So inputfield dependencies are not needed (but thx for the idea, never used dependencies so will have to look at this cool feature).

The table field option is not one I had considered or ever used before. Tried it out and it seems to cover all the bases very nicely, so this is probably the way to go.

What is the difference between a table field and the profields table? Ryan mentioned in a post I have since lost that the profields are more efficient, can anyone elaborate on this? Is the upgrade to pro worthwhile - how often are developers utilizing the other fields available in profields?

Link to comment
Share on other sites

The main difference is this:

  • When creating, editing or deleting elements in a PageTable field, you are creating, editing and deleting independent pages, which appear in your page structure. Each element can be viewed, edited and deleted separately in the Page List. Since each element is a page, it can also appear as a result from a $pages->find() query. As the name implies, the PageTable field is simply a table of links to pages, and in this sense, it is very similar to a simple multi-page field.
  • When creating, editing or deleting elements in a Profields Table, you are creating, editing and deleting rows in a table in the database. The elements can't be viewed, edited or deleted except through the owning page, and when querying, you get the owning page rather than the table row.

In terms of efficiency, the Profield Table is better, since it allows for less queries/joins to get the different values. Generally speaking, Processwire stores the value of each field in a separate table, so you have a fields_question table, a fields_answer table, a fields_display table, etc. If you want to show all three fields for a page, the system will have to query three different tables to get the values. That's how things work for the PageTable field, since it creates normal pages.

The Profields Table field on the other hand stores values for the different columns in a single table. So if you have a Profield Table field called questions with columns called "question", "answer" and "display", you will have a single table called fields_questions with columns called "question", "answer" and "display". When accessing the values of a row, it is more efficient, since you get all three values in the same query to the database.

The Profield Table has however some drawbacks:

  • The list of types you can use for the different columns is limited: you don't have a page field, or a file field for example. Since elements in a PageTable field are normal pages, you have access to all field types. The options on those fields (dependencies, visibility, etc.) are also limited.
  • The queries that you can do are also more limited, since you can't query directly for table rows.

As an example for the last point, let's say that you have a questionnaire with several questions. If you use a PageTable field called questions that references a question template (with topic, question, answer, display and include_in_email fields), you can count how many people answered that they had children like this:

$pages->find("template=question, topic=children, answer=yes");

If you use a Profield Table, that won't work, since you can't search by question (@field.subfield selectors as presented here also don't work).

In your case, I think that the best approach is to use PageTable fields as explained in my previous post.

  • Like 7
Link to comment
Share on other sites

Holy hell that's a bloody brilliant answer, ESRCH you are the man!

I've done this with a pageTable as you described and the result is perfect. But even better is the explanation of the difference between pro table and pageTable, and the way the data is stored. This explanation also gives me a better insight into why Ryan chose to have each field in PW as it's own table rather than have all fields for a page stored in one row in a pages table (like modx used to I think). This is something that always bothered me a little.

response #5 should be pinned.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...