Jump to content

Simple poll


apeisa
 Share

Recommended Posts

Client needs to create simple polls (or questionnaires) like this:

Choose what describes you best:

1) Awesome
2) Smart
3) Polite

And then on the site people can click on one options and see results.

I started to think that this should be done with pages, where poll is just template. But what is difficult now is to create those options (this goes back to "matrix" again, I think). So we need 2-n options, which should have title, but also value inside.

I'm in little bit hurry with this one, so I am ok with not-so-perfect solution. My plan is to create new FieldtypeValueKey, which holds just text title + value. These should also work like images, files etc, that you can put more than one in one field.

This FieldtypeValueKey should be usable on other cases than only polls, so I think it is better solution than custom poll module. It is nowhere near "matrix" vision, but could prove useful.

If there is simpler solution or something else I haven't figured, please tell me now :) I'll probably code this during weekend / tomorrow.

Link to comment
Share on other sites

I like your idea of the FieldtypeValueKey! But if you needed to do something really quickly, here are two other options to consider:

1. Use polldaddy and be done with it. :)

2. OR: Use pages:

Templates:
    - poll_question (fields: title) [set required child template to be poll_answer]
    - poll_answer (fields: title, total:integer)

Pages: 
    - poll_question: title=Choose what describes you best: 
         - poll_answer: title=Awesome
         - poll_answer: title=Smart
         - poll_answer: title=Polite

Here's one way the poll_question template might work (written in the browser, so please excuse errors). But this might have similarities to how you'd implement it with a Fieldtype too.

<?php

// display the question
echo "<h1>{$page->title}</h1>"; 

$displayResults = false;

if($session->get("poll" . $page->id)) {
    // if they already answered the poll this session, just display results
    $displayResults = true; 

} else if($input->post->submit_answer) {
    // if answer submitted, save it
    $answer_id = (int) $input->post->answer; 
    $answer = $page->child("id=$answer_id"); 
    if($answer->id) {
        $answer->total = $answer->total + 1;
        $answer->save(); 
    }
    echo "<p>Your answer was saved.</p>";

    // save the poll ID in session to remember they already did it
    $session->set("poll" . $page->id, true); 
    $displayResults = true; 

} else {
    // they haven't answered the poll yet, show the form: 
    echo "<form action='./' method='post'>";
    foreach($page->children as $answer) {
        echo "<label><input type='radio' name='answer' value='{$answer->id}' /> {$answer->title}</label>";
    }
    echo "<input type='submit' name='submit_answer' value='submit' />";
    echo "</form>";
}

if($displayResults) {
    // display the poll results
    $allTotal = 0; 
    foreach($page->children as $answer) $allTotal += $answer->total;
    echo "<h2>$allTotal people responded to the poll:</h2>";
    foreach($page->children as $answer) {
        $percent = round(($answer->total / $allTotal) * 100) . "%";
        echo "<p>{$answer->title}: $percent</p>"; 
    }
} 

Then, in the template where you want to display the poll:

<?php
$poll = $pages->get("/path/to/poll/you/want/"); 
echo $poll->render(); 

I know you know how to do all this, so this example is just for fun (and procrastination on another project, hehe) and and I'm sure you have something better in mind. But I'm particularly interested in learning more about the FieldtypeValueKey you mentioned.

Thanks,

Ryan

Link to comment
Share on other sites

This goes back to the whole 'matrix' idea we brought up a while ago...

I've been trying to do a similar sort of thing recently, and I still think that a matrix style solution is the best way to handle things like this.

For example, on the backend the user may manage this page like so:

http://cl.ly/2Z2O2c31230X36173j3v

If we could define fields which could be repeatable, and sortable (drag and drop) - almost exactly how images work, this would be awesome.

Thoughts?

Link to comment
Share on other sites

Ryan: thanks for your detailed (read: complete) example again! I ended up for even simpler solution here. In this case it will be always "yes" or "no" answer, so this went with super simple page where title = question and also two hidden integer fields (yes & no). I created simple ajax voting (works without js also - though I might change this, if it seems that bots and spiders are too eager to vote) here.

Almonk: yes, in many scenarios (like images, files & comments currently) repeatable elements are very much needed. Often we can get good solution with different pages, but it really shows it's limits when things get more complicated than simple poll. If you would need new page for every image, it would be messy to have anything else under that page. But matrix is not very simple scenario, as we know. Currently focus is to get 2.1 out as stable version and after that hit language support. But I would love to use something like matrix in EE is in PW.

Link to comment
Share on other sites

  • 4 months later...

I will build the full scale "poll" module soon, and started again thinking about building that ValueKey fieldtype / inputfield. Although I think that it could be named simply as FieldtypeList.

Idea is to have repeatable text fields, that can have additional value also. UI could be very similar to what Almonk posted earlier: http://cl.ly/2Z2O2c31230X36173j3v

What would be best (=simplest) way to build this? I am thinking between FieldtypeMulti or regular Fieldtype and saving values & keys as JSON and the latter feels like simpler solution here - although not sure how well it scales when I need to add things like sorting etc.

Link to comment
Share on other sites

When I needed something like this (though not dynamically updated, only admin-updated), I create pure text field, without TinyMCE, and written the custom format in CSV there. If you select your character correctly, it's also quite readable, like so:

option1 _ 540 _ I think it's very cool!
option2 _ 650 _ I'd rather not do it 
option3 _ 20 _ Absolutely not!

And then, I created custom field formatter (this is full code, only stripped of my header comments:). Just now I realized, that outside of the module, you could also add encoding function in static class (so it's globaly available everytime you call this file)


<?php

/**
* Custom Textformatter
*
* Takes saved textarea and parses it into array of values
*  *
*/

class TextformatterCustomFormatter extends Textformatter {

public static function getModuleInfo() {
	return array(
		'title' => '-- stripped title--',
		'version' => 100, 
		'summary' => "Parses textarea by new lines – \\n & '_'", 
	); 
}

public function format(&$str) {
	if (empty($str)) return;
	$retArray = array(); $inArray = array();
	$inArray = explode ("\n",trim($str));
	foreach ($inArray as $i){
		$i = explode('_',trim($i));
		foreach($i as &$inItem) $inItem = trim($inItem);
		$returnItem = (object)array (
			'votes'=>intval($i[1]),
			'text'=>$i[2]
		);
		$retArray[$i[0]] = $returnItem;
	}
	$str = $retArray;
}
}

public class CustomTF {
  public static function encode($inArray){
    $outString = '';
    foreach ($inArray as $opt=>&$iA){
      $iA = implode (' _ ', array($opt, $iA->votes, $iA->text));
    }
    $outString = implode ("\n", $inArray);
    return ($outString);
  }
}

and now, in your update function, you do this (I assume $answerVoted to have sanitized option ID ['option1' for instance]):

<?php
  $pollOptions = $page->options;
  $pollOptions[$answerVoted]->votes++;
  $page->options = CustomTF::encode($pollOptions);
  $page->save('options');
Link to comment
Share on other sites

Thanks for the example Adam. The UI is the most important thing here: It needs to be simple and easy solution. I don't want those values be editable (or at least behind setting) and it should be error free: no way to input it wrong.

In templates usage should be something like this:

<?php

foreach($p->poll as $poll) {
  echo "{$poll->question} voted {$poll->value} times";
}

The biggest reason why I don't like using pages & templates here is that it would be cumbersome to manage. You would need to have /polls/ page where you add all your polls. Then you would need to have page field where you choose what polls you want to show on page you are editing. I like it more straightforward: you just add "poll" field to templates where you allow polls and you can use this field to create polls on the fly.

But now that I wrote that down I realize few mistakes in my thinking. There wouldn't be poll archive. Also polls created this way would need checkbox (active/unactive)... plus it would allow only one poll per page. Also that wouldn't allow things like "show latest poll" etc.

So I might go back to what Ryan originally suggested (using pages and templates). That means though that I don't get my hands dirty with fieldtypes yet... :)

Link to comment
Share on other sites

But now that I wrote that down I realize few mistakes in my thinking. There wouldn't be poll archive. Also polls created this way would need checkbox (active/unactive)... plus it would allow only one poll per page. Also that wouldn't allow things like "show latest poll" etc.

I don't think that any of these would be actual limitations, it would just determine what approach you take. But if the subject is still "simple poll", then it's hard to get simpler than pages. :) You'd have a /tools/polls/ section or something, and then a page reference field would let you select what polls you want to show on any given page. Though I understand your desire to build this as a Fieldtype, so if you want to go that route lets keep talking about approach and we can figure out a good one.

Link to comment
Share on other sites

I don't think that any of these would be actual limitations, it would just determine what approach you take. But if the subject is still "simple poll", then it's hard to get simpler than pages. :) You'd have a /tools/polls/ section or something, and then a page reference field would let you select what polls you want to show on any given page.

Yep - the more I think of it, the more likely I will build this with just templates & pages. Our upcoming default site profile will at least have image carousels and taxonomy managed under /tools/ tab, so it would be just wise to use that same natural "pw-way" here with polls too.

Though I understand your desire to build this as a Fieldtype, so if you want to go that route lets keep talking about approach and we can figure out a good one.

I am waiting for a perfect moment to dive into fieldtypes, since those are still little bit mysterious for me. But it seems that this is not that moment ,)

Link to comment
Share on other sites

  • 2 weeks later...

Using Ryan's example I've made some polls.

I've made a field named poll (type:page) and it has "Parent of selectable pages" set to Poll (the page in the root that hold numerous polls).

How can I set the default poll in various pages? For example, on home page I want to display "Poll One" and on some subpage I want to display "Poll Two"?

I can select it through the admin by the poll field, but how can I output it in the templates that way?

Link to comment
Share on other sites

Using Ryan's example I've made some polls.

I've made a field named poll (type:page) and it has "Parent of selectable pages" set to Poll (the page in the root that hold numerous polls).

How can I set the default poll in various pages? For example, on home page I want to display "Poll One" and on some subpage I want to display "Poll Two"?

I can select it through the admin by the poll field, but how can I output it in the templates that way?

Not sure where you got problems. I assume you have created it with the code of Ryan on this page further above?

You can use this code as is, just insert following before $answer->save();

<?php
$answer->setOutputFormatting(false);

Make this code of Ryan a template "poll.php", in PW this will be the poll (question) template, containing the answer pages later.

Now, you already got your reference page field called "poll" or "poll_selected".

So on the template that uses this field to select a poll, you could make it like the following using the "render" method. This is a module under "Page" section called "Page render" you need to install in case you haven't already. This adds render method to all pages. Now using this method it's as simple as:

<?php
// output poll where you want in you page templates
if($page->poll_selected){
echo $page->poll_selected->render();
{
Link to comment
Share on other sites

Thanks Soma, for your answer.

The thing is that I already have a working poll including

<?php $answer->setOutputFormatting(false); ?>

I use this code to render the poll

<?php
if(count($page->poll)) {
   foreach($page->poll as $poll) {
   echo $poll->render();
   }
}
?>

and it renders poll just fine, but when I have more than one poll in Poll page located in root of the site, for example:

Poll

-- Poll 1

-- Poll 2

it renders both of the polls on the same page. I can render only one poll, but then I need to unpublish other polls located under same parent where all polls reside.

Because of that I've made a field named poll (type: page) where I can select what polls I want to use.

The question is: How can I use "Poll 1" for example on one page, and "Poll 2" on another page, given that page(s) uses template that contains field "poll" where I can select poll I want to appear?

I want to avoid showing multiple polls on one page at the same time and I want to choose different poll for different pages...

Link to comment
Share on other sites

Because of that I've made a field named poll (type: page) where I can select what polls I want to use.

The question is: How can I use "Poll 1" for example on one page, and "Poll 2" on another page, given that page(s) uses template that contains field "poll" where I can select poll I want to appear?

Exactly how you're doing it already and how I explained. I'm a little confused.

To clarify again. You have a page field named "poll". This is set to allow only 1 page reference "Single page (Page) or boolean false when none selected", and set parent to be the parent page "Poll" containing all the polls (Poll1,Poll2). Then, on page you select the poll you wish to output like --Poll1. So you got 1 Poll selected, and in the template of the page there would be this code:

<?php
if($page->poll) {
   echo $page->poll->render();
}
?>
Link to comment
Share on other sites

Just noticed a typo in my code it should of course be:

<?php
if($page->poll) {
   echo $page->poll->render();
}
?>

But I think you noticed that too? cause it wouldn't have outputed something at all with $poll->render();

If it still does not work, you're doing something wrong in setting this up all. Not sure how I can further help without seeing the code and field/template setup.

1. I 100% think you forgot this: Make sure the poll page select field is set to allow single pages only (like I mentioned in my previous post). Having different setup wouldn't work since it would return page array when with multiple. You would have to change my code to $page->poll->first()->render();  I think.

<?php
if(count($page->poll) > 0) {
   echo $page->poll->first()->render();
}
?>

2. The Poll1,Poll2 uses template that has code from ryan, thats going to render.

I have set up a testcase locally within 5 minutes and it works well.

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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...